Skip to content

feat(mcp): add public AI-Q MCP server#319

Open
tanleach wants to merge 33 commits into
NVIDIA-AI-Blueprints:release/2.2from
tanleach:feat/mcp-phase1
Open

feat(mcp): add public AI-Q MCP server#319
tanleach wants to merge 33 commits into
NVIDIA-AI-Blueprints:release/2.2from
tanleach:feat/mcp-phase1

Conversation

@tanleach

@tanleach tanleach commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Overview

Add a standalone, public AI-Q MCP server under mcp/ without the MaaS/MOS SDK. The server exposes exactly three stateless Streamable HTTP tools—submit_query, poll_query, and get_final_report—and keeps asynchronous research jobs in PostgreSQL while reusing the existing AI-Q/NAT workflow.

This change also adds the public NIM + Tavily workflow config, container/Compose assets, user and security documentation, compatibility tests, release smoke tests, dependency/license evidence, and protected CI coverage.

Key scope and security boundaries:

  • MCP calls are intentionally unauthenticated. Every request uses the constant anonymous principal, and each random job UUID is a bearer capability.
  • AIQ_MCP_ALLOWED_HOSTS, AIQ_MCP_ALLOWED_ORIGINS, and CORS are DNS-rebinding/browser safeguards; they are not identity or authorization controls.
  • The endpoint should remain on a trusted network or behind an authenticated/rate-limited gateway when deployed beyond local use.

The frozen compatibility contract and intentional public adaptations are documented in mcp/REFERENCE_PARITY.md. Tool schemas, state transitions, polling cadence, PostgreSQL persistence, background-task ownership, todo normalization, and stable client error shapes remain compatible. The intentional adaptations are FastMCP transport/lifecycle ownership, anonymous capability access, public configuration, capability-safe logging, and deployment-owned TLS.

Release-review follow-ups are explicit in mcp/SECURITY.md:

  • the unfiltered audit evidence retains three canonical no-fixed-version transitive advisories, with reachability analysis and automatic failure when a fixed version appears;
  • six exact license/NOTICE findings remain manual_review_required for the releasing organization's legal/NOTICE review;
  • target-specific license review is required before publishing a non-Linux/CPython 3.13 image or relying on the generic Python 3.11–3.13 wheel as a release artifact.

Validation

  • uv run pre-commit run --all-files — all hooks passed, including Ruff, lock validation, secret detection, YAML checks, and Markdown link checks.

  • PostgreSQL-backed MCP suite — 174 passed, 0 skipped, 96.67% coverage (90% gate).

  • Complete workspace suite — 1,542 passed, 8 skipped, 0 failed.

  • Frozen tool-contract extraction — exact ordered three-tool contract SHA-256 81eba67fadd56e64b58a84b700b202841f8636c93c6cbf63752507c8bf5ca96a.

  • actionlint .github/workflows/ci.yml — passed with actionlint v1.7.12.

  • Sphinx documentation build — 62 pages built; only three unrelated pre-existing missing-xref warnings.

  • Production-only uv sync --frozen --package aiq-mcp-server --no-dev --no-default-groups --no-editable plus mcp/scripts/check_runtime_dependencies.py — passed.

  • Unfiltered and exception-gated uv audit, CycloneDX 1.5 SBOM generation, and exact license inventory — passed the documented engineering gates; evidence is archived by Script Validation.

  • MCP wheel build — verified embedded Apache-2.0 license metadata.

  • Release Compose image boot — exact /live and /health payloads, GET /mcp 405 contract, anonymous initialization, exact tool listing, and unknown-capability response passed through mcp/scripts/protocol_smoke.py.

  • I ran the relevant local checks or explained why they are not applicable.

  • I added or updated tests for behavior changes.

  • I updated documentation for user-facing or contributor-facing changes.

  • I confirmed this PR does not include secrets, credentials, or internal-only data.

  • I certify this contribution under the Developer Certificate of Origin (DCO) and signed my commits with git commit -s or an equivalent sign-off.

Where should reviewers start?

  1. docs/source/integration/mcp-server.md for the user-facing protocol, deployment, and security model.
  2. mcp/REFERENCE_PARITY.md for the compatibility boundary and intentional differences.
  3. mcp/src/aiq_mcp/server.py and mcp/src/aiq_mcp/jobs.py for transport/lifecycle and state behavior.
  4. .github/workflows/ci.yml and mcp/SECURITY.md for mandatory test, SBOM, audit, license, and release-image gates.

Related Issues

Summary by CodeRabbit

  • New Features
    • Added a standalone MCP Server run mode with submit_query, poll_query, get_final_report, plus config_mcp.yml.
    • Added a local Docker Compose MCP stack with Postgres, loopback-only ports, /live + /health, and protocol smoke testing.
  • Bug Fixes
    • Improved log redaction for identifiers and sanitized user-facing error persistence to avoid leaking raw exception details.
  • Documentation
    • Expanded MCP server/integration docs, including transport/health contracts, security guidance, and compatibility/reference docs.
  • Tests / CI
    • Strengthened MCP contract, Postgres-backed coverage, and release evidence checks, including coverage gating and enhanced runtime/package validation.

@copy-pr-bot

copy-pr-bot Bot commented Jul 8, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: e1d2eb68-2137-44fa-90a8-71d8ddbce459

📥 Commits

Reviewing files that changed from the base of the PR and between d90bc8a and e06daa5.

📒 Files selected for processing (2)
  • mcp/src/aiq_mcp/job_store.py
  • mcp/tests/test_postgres_job_store.py
 _______________________________________________________________
< Ghost in the Shell (Script): Stand Alone Complex Code Review. >
 ---------------------------------------------------------------
  \
   \   (\__/)
       (•ㅅ•)
       /   づ

Walkthrough

This PR adds a standalone MCP server with PostgreSQL-backed jobs, Streamable HTTP tools, isolated packaging and CI, Docker/Compose deployment, release validation, workflow failure contracts, and identifier-log redaction.

Changes

AI-Q MCP Server

Layer / File(s) Summary
MCP contracts and configuration
configs/config_mcp.yml, mcp/pyproject.toml, mcp/REFERENCE_PARITY.md, src/aiq_agent/agents/chat_researcher/models/*
Defines MCP configuration, packaging metadata, compatibility requirements, and explicit workflow outcome models.
PostgreSQL jobs and checkpoint state
mcp/src/aiq_mcp/job_store.py, mcp/src/aiq_mcp/jobs.py, mcp/src/aiq_mcp/checkpoint_todos.py, mcp/deploy/init-mcp-db.sql
Adds persistent job lifecycle operations, reconciliation, polling/report shaping, checkpoint todo retrieval, and schema initialization.
Server runtime and protocol
mcp/src/aiq_mcp/server.py, mcp/src/aiq_mcp/workflow_runner.py, mcp/scripts/protocol_smoke.py
Adds FastMCP/Starlette lifecycle wiring, anonymous capability tools, health and transport policies, workflow execution, and protocol smoke validation.

Packaging, deployment, and validation

Layer / File(s) Summary
Isolated workspace and CI
.github/workflows/ci.yml, .pre-commit-config.yaml, pyproject.toml, scripts/*
Separates MCP dependency resolution, adds PostgreSQL-backed tests and coverage gates, and runs release evidence checks.
Containers and release evidence
mcp/Dockerfile, deploy/compose/*, mcp/scripts/check_*, mcp/tests/test_deployment_assets.py, mcp/tests/test_release_checks.py
Adds reproducible non-root images, health-gated Compose services, dependency verification, SBOM/license evidence, and packaging contracts.
MCP documentation
README.md, mcp/README.md, docs/source/integration/*, docs/source/deployment/*, mcp/SECURITY.md
Documents MCP tools, endpoints, lifecycle, security boundaries, deployment, compatibility, and release policies.

Existing workflow hardening

Layer / File(s) Summary
Failure outcomes and identifier redaction
src/aiq_agent/agents/chat_researcher/*, src/aiq_agent/common/logging_utils.py, src/aiq_agent/knowledge/summary_store.py, frontends/aiq_api/src/aiq_api/jobs/runner.py, tests/*
Adds explicit terminal workflow failures, preclassified depth reuse, hashed log references, hidden SQL parameters, and sanitized persisted errors.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant MCPRuntime
  participant JobManager
  participant JobStore
  participant WorkflowRunner
  Client->>MCPRuntime: submit_query(query)
  MCPRuntime->>JobManager: submit(query, anonymous)
  JobManager->>WorkflowRunner: classify(query)
  JobManager->>JobStore: create queued job
  JobManager->>WorkflowRunner: run_query(query, conversation_id)
  WorkflowRunner-->>JobManager: workflow outcome
  JobManager->>JobStore: update terminal state
  Client->>MCPRuntime: poll_query(job_id)
  MCPRuntime->>JobManager: poll(job_id, anonymous)
  JobManager->>JobStore: record_poll(job_id, anonymous)
  Client->>MCPRuntime: get_final_report(job_id)
  MCPRuntime->>JobManager: get_final_report(job_id, anonymous)
  JobManager->>JobStore: get(job_id)
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.37% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title follows Conventional Commits and accurately summarizes the main change: a new public AI-Q MCP server.
Description check ✅ Passed The description matches the required template and includes overview, validation, reviewer starting points, and related issue details.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@AjayThorve AjayThorve added this to the v2.2 milestone Jul 8, 2026
@tanleach tanleach marked this pull request as ready for review July 8, 2026 23:17
@tanleach tanleach requested a review from AjayThorve July 8, 2026 23:17

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
.github/workflows/ci.yml (1)

91-95: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Pin uv version consistently across jobs.

The test job's Setup uv step has no version: pin, while test-scripts (Line 186) pins 0.11.26. Different jobs in the same workflow run can silently resolve different uv versions, undermining the reproducibility the version pin in test-scripts is meant to guarantee.

As per path instructions, .github/** changes should be reviewed for "reproducible uv/npm setup."

♻️ Proposed fix
       - name: Setup uv
         uses: astral-sh/setup-uv@v4
         with:
           enable-cache: true
+          version: "0.11.26"

Also applies to: 182-186

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci.yml around lines 91 - 95, The Setup uv steps in the
workflow are inconsistent because the test job uses astral-sh/setup-uv@v4
without a version pin while the test-scripts job already pins uv, so align both
jobs to the same fixed uv version. Update the Setup uv configuration in the
workflow so the test and test-scripts jobs use the same version value, keeping
the version reference attached to the astral-sh/setup-uv@v4 step.

Source: Path instructions

mcp/tests/conftest.py (1)

1-19: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Avoid relying on pytest’s importlib namespace setup. This shim is tied to --import-mode=importlib package resolution, which changed in pytest 8.2; if collection behavior shifts or the mode changes, mcp can be shadowed again. A less order-dependent import path would make this safer.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mcp/tests/conftest.py` around lines 1 - 19, The pytest collection shim in
conftest.py is too dependent on importlib-mode namespace behavior, so replace
the current sys.modules cleanup plus
importlib.import_module("mcp.server.fastmcp") approach with a more direct,
order-independent way to ensure the installed MCP package is imported. Update
the logic around protocol_package and the mcp module handling so it explicitly
resolves the dependency package before tests run, avoiding reliance on pytest’s
collection-created namespace module. Keep the fix localized to the conftest.py
import bootstrap path and preserve the intended fastmcp import without depending
on collection order.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/ci.yml:
- Line 68: The CI workflow uses mutable references for the postgres service
image and the upload-artifact actions, so update the workflow to pin those
dependencies to immutable digests/SHA references. In the workflow definition,
replace the postgres service reference and both uses of actions/upload-artifact
with digest-pinned versions, keeping the existing job behavior unchanged while
making the references reproducible and safer to review.

In `@mcp/src/aiq_mcp/jobs.py`:
- Around line 344-349: The `_heartbeat_job` loop should not die on a transient
`self._store.heartbeat(job_id, self._runner_id)` failure; wrap the heartbeat
call in exception handling similar to `_reconcile_jobs_periodically` so the task
keeps running and logs the error. Add a broad catch inside `_heartbeat_job` with
a retry-after-sleep behavior, and make sure the `JobRunner` cleanup path in
`_run_job` still discards the job from `_FAILURE_HANDLER` even if the heartbeat
task ends unexpectedly.

In `@mcp/src/aiq_mcp/server.py`:
- Around line 331-394: `submit_query` currently accepts unlimited anonymous
requests with an unbounded `query` string, so add abuse controls around this
public entrypoint. Enforce a maximum query length before calling
`_get_jobs().submit`, and add a per-IP or global submission rate limit for the
unauthenticated flow, preferably in the MCP server stack (for example via
Starlette middleware or upstream proxy/ingress). Use `submit_query`,
`_get_jobs`, and the anonymous-principal path as the key locations to update.

In `@mcp/tests/test_client_session_integration.py`:
- Around line 416-434: The skip/warning text in the phase6_postgres_url fixture
is embedding the raw exception string, which can leak DSN or credential-related
details. Update the exception handling around _ensure_database and _reset_schema
to use only the exception type name from asyncpg.PostgresError/OSError instead
of interpolating exc directly, while keeping the existing pytest.skip and
warnings.warn behavior and the same fixture flow.

In `@src/aiq_agent/common/logging_utils.py`:
- Around line 9-12: The log_identifier_ref helper currently uses plain SHA-256,
which is deterministic but easier to brute-force for low-entropy identifiers.
Update log_identifier_ref in logging_utils to use a keyed hash such as HMAC with
a server-side secret while preserving the same stable output contract and
sha256:-prefixed 12-character hex format. Keep the existing test expectations in
mind: deterministic for the same input, does not reveal the original identifier,
and still returns exactly 12 hex characters after the prefix.

---

Outside diff comments:
In @.github/workflows/ci.yml:
- Around line 91-95: The Setup uv steps in the workflow are inconsistent because
the test job uses astral-sh/setup-uv@v4 without a version pin while the
test-scripts job already pins uv, so align both jobs to the same fixed uv
version. Update the Setup uv configuration in the workflow so the test and
test-scripts jobs use the same version value, keeping the version reference
attached to the astral-sh/setup-uv@v4 step.

In `@mcp/tests/conftest.py`:
- Around line 1-19: The pytest collection shim in conftest.py is too dependent
on importlib-mode namespace behavior, so replace the current sys.modules cleanup
plus importlib.import_module("mcp.server.fastmcp") approach with a more direct,
order-independent way to ensure the installed MCP package is imported. Update
the logic around protocol_package and the mcp module handling so it explicitly
resolves the dependency package before tests run, avoiding reliance on pytest’s
collection-created namespace module. Keep the fix localized to the conftest.py
import bootstrap path and preserve the intended fastmcp import without depending
on collection order.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: cbcc9fa2-3a60-49b5-a035-04b70d24b653

📥 Commits

Reviewing files that changed from the base of the PR and between 36c7854 and 9fa2afb.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (51)
  • .dockerignore
  • .github/workflows/ci.yml
  • .pre-commit-config.yaml
  • .secrets.baseline
  • LICENSE-THIRD-PARTY
  • README.md
  • configs/config_mcp.yml
  • deploy/compose/docker-compose.mcp.yaml
  • docs/source/index.md
  • docs/source/integration/index.md
  • docs/source/integration/mcp-server.md
  • mcp/Dockerfile
  • mcp/LICENSE
  • mcp/README.md
  • mcp/REFERENCE_PARITY.md
  • mcp/SECURITY.md
  • mcp/deploy/README.md
  • mcp/deploy/init-mcp-db.sql
  • mcp/pyproject.toml
  • mcp/scripts/check_license_inventory.py
  • mcp/scripts/check_runtime_dependencies.py
  • mcp/scripts/protocol_smoke.py
  • mcp/src/aiq_mcp/__init__.py
  • mcp/src/aiq_mcp/checkpoint_todos.py
  • mcp/src/aiq_mcp/db_url.py
  • mcp/src/aiq_mcp/job_store.py
  • mcp/src/aiq_mcp/jobs.py
  • mcp/src/aiq_mcp/server.py
  • mcp/src/aiq_mcp/workflow_runner.py
  • mcp/tests/conftest.py
  • mcp/tests/test_checkpoint_todos.py
  • mcp/tests/test_client_session_integration.py
  • mcp/tests/test_config_and_packaging.py
  • mcp/tests/test_db_url.py
  • mcp/tests/test_dependency_compatibility.py
  • mcp/tests/test_deployment_assets.py
  • mcp/tests/test_imports.py
  • mcp/tests/test_job_store.py
  • mcp/tests/test_jobs.py
  • mcp/tests/test_postgres_job_store.py
  • mcp/tests/test_release_checks.py
  • mcp/tests/test_runtime_dependencies.py
  • mcp/tests/test_server_runtime.py
  • mcp/tests/test_workflow_runner.py
  • pyproject.toml
  • src/aiq_agent/agents/chat_researcher/register.py
  • src/aiq_agent/common/logging_utils.py
  • src/aiq_agent/knowledge/summary_store.py
  • tests/aiq_agent/agents/chat_researcher/test_register_helpers.py
  • tests/aiq_agent/common/test_logging_utils.py
  • tests/knowledge_layer_tests/test_summary_store.py
📜 Review details
⏰ Context from checks skipped due to timeout. (2)
  • GitHub Check: Script Validation
  • GitHub Check: Pytest and Coverage
⚠️ CI failures not shown inline (2)

GitHub Actions: Skills Eval / Run Harbor skill eval: fix(mcp): upgrade NLTK security baseline

Conclusion: failure

View job details

##[group]Run if [ ! -r "$RUNNER_ENV_FILE" ]; then
 �[36;1mif [ ! -r "$RUNNER_ENV_FILE" ]; then�[0m
 �[36;1m  echo "::error::Runner credential file missing or unreadable at $RUNNER_ENV_FILE"�[0m

GitHub Actions: Skills Eval / 0_Run Harbor skill eval.txt: fix(mcp): upgrade NLTK security baseline

Conclusion: failure

View job details

##[group]Run if [ ! -r "$RUNNER_ENV_FILE" ]; then
 �[36;1mif [ ! -r "$RUNNER_ENV_FILE" ]; then�[0m
 �[36;1m  echo "::error::Runner credential file missing or unreadable at $RUNNER_ENV_FILE"�[0m
🧰 Additional context used
📓 Path-based instructions (11)
**

⚙️ CodeRabbit configuration file

**:

AI-Q Agent Guidance

Repository-global instructions for coding agents and for humans reviewing
agent-authored changes. These rules apply to every task in this repository.
Task-specific runbooks live in .agents/skills/ — load the
relevant skill before starting a workflow it covers.

Project overview

AI-Q is an NVIDIA AI Blueprint: an enterprise research agent built on the
NeMo Agent Toolkit (NAT). The deployed product is a research blueprint, not
a general skill runtime. New retrieval sources and tools are NAT functions;
agent behavior is driven by workflow YAML, Jinja2 prompts, and a data-source
registry — not by hard-coded logic.

Primary boundaries:

  • Backend Python package: src/aiq_agent/.
  • Data-source and tool packages: sources/ (each is its own package).
  • Frontends and tooling: frontends/ (web UI in frontends/ui/, eval harnesses
    in frontends/benchmarks/).
  • Configs, deployment, docs: configs/, deploy/, docs/.

Stay inside this repository. If your workspace also contains adjacent repos
(for example a sibling NeMo-Relay checkout), do not edit them as part of an AI-Q
change. Treat sources/* as independent packages: prefer the smallest change
scoped to the package you are touching.

Repository structure

Path Purpose
src/aiq_agent/ Backend agent, FastAPI extensions, auth, observability, knowledge
sources/ Data-source / tool packages (e.g. tavily_web_search, google_scholar_paper_search)
configs/ Workflow YAML configs (e.g. config_cli_default.yml)
frontends/ui/ Next.js / React / TypeScript / Tailwind / KUI web UI
frontends/benchmarks/ Eval harnesses: freshqa, deepsearch_qa, deepresearch_bench
deploy/ Docker Compose and Helm/Kubernetes assets; deploy/.env for secrets
docs/source/ ...

Files:

  • mcp/deploy/README.md
  • docs/source/integration/index.md
  • mcp/src/aiq_mcp/__init__.py
  • tests/aiq_agent/common/test_logging_utils.py
  • mcp/README.md
  • tests/aiq_agent/agents/chat_researcher/test_register_helpers.py
  • LICENSE-THIRD-PARTY
  • mcp/LICENSE
  • mcp/REFERENCE_PARITY.md
  • mcp/tests/conftest.py
  • docs/source/index.md
  • mcp/tests/test_db_url.py
  • mcp/src/aiq_mcp/db_url.py
  • mcp/tests/test_job_store.py
  • README.md
  • mcp/scripts/check_runtime_dependencies.py
  • mcp/tests/test_runtime_dependencies.py
  • mcp/pyproject.toml
  • src/aiq_agent/common/logging_utils.py
  • mcp/tests/test_imports.py
  • mcp/tests/test_dependency_compatibility.py
  • mcp/SECURITY.md
  • mcp/Dockerfile
  • mcp/tests/test_workflow_runner.py
  • mcp/scripts/protocol_smoke.py
  • tests/knowledge_layer_tests/test_summary_store.py
  • mcp/tests/test_deployment_assets.py
  • mcp/deploy/init-mcp-db.sql
  • src/aiq_agent/agents/chat_researcher/register.py
  • configs/config_mcp.yml
  • docs/source/integration/mcp-server.md
  • mcp/src/aiq_mcp/workflow_runner.py
  • src/aiq_agent/knowledge/summary_store.py
  • mcp/tests/test_release_checks.py
  • mcp/src/aiq_mcp/job_store.py
  • mcp/tests/test_client_session_integration.py
  • pyproject.toml
  • mcp/src/aiq_mcp/checkpoint_todos.py
  • mcp/scripts/check_license_inventory.py
  • mcp/tests/test_checkpoint_todos.py
  • mcp/src/aiq_mcp/server.py
  • mcp/src/aiq_mcp/jobs.py
  • deploy/compose/docker-compose.mcp.yaml
  • mcp/tests/test_jobs.py
  • mcp/tests/test_config_and_packaging.py
  • mcp/tests/test_postgres_job_store.py
  • mcp/tests/test_server_runtime.py
docs/source/**/*

📄 CodeRabbit inference engine (AGENTS.md)

Update the docs under docs/source/ when behavior, configuration, or workflows change

Files:

  • docs/source/integration/index.md
  • docs/source/index.md
  • docs/source/integration/mcp-server.md
{docs/**,README.md,CONTRIBUTING.md,SECURITY.md,CODE-OF-CONDUCT.md}

⚙️ CodeRabbit configuration file

{docs/**,README.md,CONTRIBUTING.md,SECURITY.md,CODE-OF-CONDUCT.md}: Review documentation for command accuracy, branch-name consistency, current CI and copy-pr-bot behavior, public
vs internal boundary clarity, stale examples, and links that no longer match the repository layout.

Files:

  • docs/source/integration/index.md
  • docs/source/index.md
  • README.md
  • docs/source/integration/mcp-server.md
**/*.py

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Run ruff check and ruff format validation for Python code changes

**/*.py: Python code must be linted and formatted with Ruff using line length 120, target Python 3.11, rule sets E,F,W,I,PL,UP, and isort force-single-line configuration
Never commit secrets, tokens, or environment-specific hostnames; use environment variables and SecretStr instead, resolving API keys at runtime
Never print or log secret values, including in tool output or error messages
Missing-secret paths must degrade gracefully (stub/skip), not crash or leak
Do not hand-reformat unrelated code when making changes; match the existing import and formatting style

Files:

  • mcp/src/aiq_mcp/__init__.py
  • tests/aiq_agent/common/test_logging_utils.py
  • tests/aiq_agent/agents/chat_researcher/test_register_helpers.py
  • mcp/tests/conftest.py
  • mcp/tests/test_db_url.py
  • mcp/src/aiq_mcp/db_url.py
  • mcp/tests/test_job_store.py
  • mcp/scripts/check_runtime_dependencies.py
  • mcp/tests/test_runtime_dependencies.py
  • src/aiq_agent/common/logging_utils.py
  • mcp/tests/test_imports.py
  • mcp/tests/test_dependency_compatibility.py
  • mcp/tests/test_workflow_runner.py
  • mcp/scripts/protocol_smoke.py
  • tests/knowledge_layer_tests/test_summary_store.py
  • mcp/tests/test_deployment_assets.py
  • src/aiq_agent/agents/chat_researcher/register.py
  • mcp/src/aiq_mcp/workflow_runner.py
  • src/aiq_agent/knowledge/summary_store.py
  • mcp/tests/test_release_checks.py
  • mcp/src/aiq_mcp/job_store.py
  • mcp/tests/test_client_session_integration.py
  • mcp/src/aiq_mcp/checkpoint_todos.py
  • mcp/scripts/check_license_inventory.py
  • mcp/tests/test_checkpoint_todos.py
  • mcp/src/aiq_mcp/server.py
  • mcp/src/aiq_mcp/jobs.py
  • mcp/tests/test_jobs.py
  • mcp/tests/test_config_and_packaging.py
  • mcp/tests/test_postgres_job_store.py
  • mcp/tests/test_server_runtime.py
{.github/**,ci/**,.pre-commit-config.yaml,pyproject.toml,uv.lock}

⚙️ CodeRabbit configuration file

{.github/**,ci/**,.pre-commit-config.yaml,pyproject.toml,uv.lock}: Review automation and packaging changes for least-privilege permissions, pinned versions where appropriate,
copy-pr-bot pull-request/ branch behavior, reproducible uv/npm setup, secret handling, and consistency with
the documented validation matrix.

Files:

  • .pre-commit-config.yaml
  • pyproject.toml
  • .github/workflows/ci.yml
**/*test*.py

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Run pytest for all behavior changes in Python code

Files:

  • tests/aiq_agent/common/test_logging_utils.py
  • tests/aiq_agent/agents/chat_researcher/test_register_helpers.py
  • mcp/tests/conftest.py
  • mcp/tests/test_db_url.py
  • mcp/tests/test_job_store.py
  • mcp/tests/test_runtime_dependencies.py
  • mcp/tests/test_imports.py
  • mcp/tests/test_dependency_compatibility.py
  • mcp/tests/test_workflow_runner.py
  • tests/knowledge_layer_tests/test_summary_store.py
  • mcp/tests/test_deployment_assets.py
  • mcp/tests/test_release_checks.py
  • mcp/tests/test_client_session_integration.py
  • mcp/tests/test_checkpoint_todos.py
  • mcp/tests/test_jobs.py
  • mcp/tests/test_config_and_packaging.py
  • mcp/tests/test_postgres_job_store.py
  • mcp/tests/test_server_runtime.py
src/aiq_agent/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

src/aiq_agent/**/*.py: Respect authenticated data sources by honoring requires_auth, per-user token pass-through, and backend token validators; apply owner guardrails before loading protected report or artifact context into an agent
Do not weaken or bypass AuthMiddleware, validators, or auth gating without a prior design discussion

Files:

  • src/aiq_agent/common/logging_utils.py
  • src/aiq_agent/agents/chat_researcher/register.py
  • src/aiq_agent/knowledge/summary_store.py
src/aiq_agent/agents/**/*

⚙️ CodeRabbit configuration file

src/aiq_agent/agents/**/*: Review agent changes for research workflow correctness, graph state transitions, prompt/tool contracts,
HITL behavior, and failure handling. Flag changes that weaken source attribution, report generation,
async cancellation, checkpointing, or data-source selection without focused tests and docs.

Files:

  • src/aiq_agent/agents/chat_researcher/register.py
{deploy/**,configs/**}

⚙️ CodeRabbit configuration file

{deploy/**,configs/**}: Review deployment and config changes for secret separation, safe defaults, local-vs-production behavior, Helm and
Docker portability, and documentation parity. Flag committed credentials, environment-specific NVIDIA internals in
public defaults, and changes that make examples diverge from CI-tested paths.

Files:

  • configs/config_mcp.yml
  • deploy/compose/docker-compose.mcp.yaml
{src/aiq_agent/knowledge/**,sources/**}

⚙️ CodeRabbit configuration file

{src/aiq_agent/knowledge/**,sources/**}: Review data-source and knowledge-layer changes for optional dependency boundaries, external API error handling,
retry/rate-limit behavior, deterministic tests, and registration consistency. New source packages should include
package metadata, plugin registration when applicable, and source-level tests.

Files:

  • src/aiq_agent/knowledge/summary_store.py
**/*config*.py

📄 CodeRabbit inference engine (AGENTS.md)

Config schemas must inherit from FunctionBaseConfig and YAML _type names must come from the registered config class

Files:

  • mcp/tests/test_config_and_packaging.py
🪛 ast-grep (0.44.1)
mcp/scripts/check_runtime_dependencies.py

[info] 89-89: use jsonify instead of json.dumps for JSON output
Context: json.dumps(result, sort_keys=True)
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)

mcp/scripts/protocol_smoke.py

[info] 137-137: use jsonify instead of json.dumps for JSON output
Context: json.dumps(result, indent=2, sort_keys=True)
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)

mcp/scripts/check_license_inventory.py

[info] 171-171: use jsonify instead of json.dumps for JSON output
Context: json.dumps(payload, sort_keys=True, separators=(",", ":"))
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)


[info] 418-418: use jsonify instead of json.dumps for JSON output
Context: json.dumps(inventory, indent=2, sort_keys=True)
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)


[info] 419-419: use jsonify instead of json.dumps for JSON output
Context: json.dumps(validation, sort_keys=True)
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)

mcp/src/aiq_mcp/server.py

[warning] 66-66: Do not make http calls without encryption
Context: "http://[::1]:*"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(requests-http)


[warning] 67-67: Do not make http calls without encryption
Context: "http://0.0.0.0:*"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(requests-http)

mcp/tests/test_server_runtime.py

[warning] 479-479: Configuring an LLM/agent client endpoint over http:// sends prompts and responses (and often API keys) in cleartext, exposing them to interception. Use https for the base_url.
Context: base_url="http://localhost"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(llm-client-insecure-http-python)


[warning] 546-546: Configuring an LLM/agent client endpoint over http:// sends prompts and responses (and often API keys) in cleartext, exposing them to interception. Use https for the base_url.
Context: base_url="http://localhost"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(llm-client-insecure-http-python)


[warning] 559-559: Configuring an LLM/agent client endpoint over http:// sends prompts and responses (and often API keys) in cleartext, exposing them to interception. Use https for the base_url.
Context: base_url="http://localhost"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(llm-client-insecure-http-python)


[warning] 566-566: Configuring an LLM/agent client endpoint over http:// sends prompts and responses (and often API keys) in cleartext, exposing them to interception. Use https for the base_url.
Context: base_url="http://localhost"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(llm-client-insecure-http-python)


[warning] 628-628: Configuring an LLM/agent client endpoint over http:// sends prompts and responses (and often API keys) in cleartext, exposing them to interception. Use https for the base_url.
Context: base_url="http://localhost"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(llm-client-insecure-http-python)


[warning] 640-640: Configuring an LLM/agent client endpoint over http:// sends prompts and responses (and often API keys) in cleartext, exposing them to interception. Use https for the base_url.
Context: base_url="http://localhost"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(llm-client-insecure-http-python)


[warning] 645-645: Configuring an LLM/agent client endpoint over http:// sends prompts and responses (and often API keys) in cleartext, exposing them to interception. Use https for the base_url.
Context: base_url="http://localhost"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(llm-client-insecure-http-python)


[warning] 661-661: Configuring an LLM/agent client endpoint over http:// sends prompts and responses (and often API keys) in cleartext, exposing them to interception. Use https for the base_url.
Context: base_url="http://localhost"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(llm-client-insecure-http-python)


[warning] 695-695: Configuring an LLM/agent client endpoint over http:// sends prompts and responses (and often API keys) in cleartext, exposing them to interception. Use https for the base_url.
Context: base_url="http://localhost"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(llm-client-insecure-http-python)


[warning] 710-710: Configuring an LLM/agent client endpoint over http:// sends prompts and responses (and often API keys) in cleartext, exposing them to interception. Use https for the base_url.
Context: base_url="http://localhost"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(llm-client-insecure-http-python)


[warning] 721-721: Configuring an LLM/agent client endpoint over http:// sends prompts and responses (and often API keys) in cleartext, exposing them to interception. Use https for the base_url.
Context: base_url="http://untrusted.example"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(llm-client-insecure-http-python)


[warning] 933-933: Configuring an LLM/agent client endpoint over http:// sends prompts and responses (and often API keys) in cleartext, exposing them to interception. Use https for the base_url.
Context: base_url="http://localhost"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(llm-client-insecure-http-python)


[warning] 721-721: Do not make http calls without encryption
Context: "http://untrusted.example"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(requests-http)


[info] 400-400: use jsonify instead of json.dumps for JSON output
Context: json.dumps(schema_contract, sort_keys=True, separators=(",", ":"))
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)

🪛 Checkov (3.3.2)
mcp/Dockerfile

[low] 10-10: Ensure the base image uses a non latest version tag

(CKV_DOCKER_7)

🪛 GitHub Actions: Skills Eval / Run Harbor skill eval
mcp/Dockerfile

[error] 79-79: Docker build failed at step [builder 14/17]: uv sync --frozen --extra s3. Error: "Failed to determine installation plan". Caused by: "Distribution not found at: file:///app/mcp". Exit code: 2.

🪛 Hadolint (2.14.0)
mcp/Dockerfile

[warning] 16-16: Pin versions in apt get install. Instead of apt-get install <package> use apt-get install <package>=<version>

(DL3008)


[warning] 65-65: Pin versions in apt get install. Instead of apt-get install <package> use apt-get install <package>=<version>

(DL3008)

🪛 OpenGrep (1.23.0)
mcp/src/aiq_mcp/job_store.py

[ERROR] 121-137: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)


[ERROR] 142-153: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)


[ERROR] 157-168: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)


[ERROR] 192-195: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)


[ERROR] 239-239: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)


[ERROR] 244-255: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)


[ERROR] 259-259: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)


[ERROR] 260-269: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)


[ERROR] 270-288: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)


[ERROR] 289-291: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)


[ERROR] 292-294: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)


[ERROR] 295-295: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)


[ERROR] 296-298: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)


[ERROR] 299-301: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)


[ERROR] 302-310: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)


[ERROR] 311-319: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)

mcp/tests/test_client_session_integration.py

[ERROR] 491-491: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)

mcp/tests/test_checkpoint_todos.py

[ERROR] 426-426: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)

mcp/tests/test_postgres_job_store.py

[ERROR] 484-484: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)

🪛 SQLFluff (4.2.2)
mcp/deploy/init-mcp-db.sql

[error] 43-43: CREATE INDEX should use CONCURRENTLY to avoid locking the table during the build.

(PG01)


[error] 44-44: CREATE INDEX should use CONCURRENTLY to avoid locking the table during the build.

(PG01)


[error] 45-45: CREATE INDEX should use CONCURRENTLY to avoid locking the table during the build.

(PG01)


[error] 46-46: CREATE INDEX should use CONCURRENTLY to avoid locking the table during the build.

(PG01)

🪛 zizmor (1.26.1)
.github/workflows/ci.yml

[error] 68-68: unpinned image references (unpinned-images): container image is not pinned to a SHA256 hash

(unpinned-images)


[error] 263-263: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 292-292: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🔇 Additional comments (59)
src/aiq_agent/agents/chat_researcher/register.py (1)

34-34: LGTM!

Also applies to: 61-65, 561-574, 618-633, 645-648

src/aiq_agent/knowledge/summary_store.py (1)

30-31: LGTM!

Also applies to: 108-108, 135-135, 153-153, 264-270, 286-290, 309-313, 328-334, 347-353, 365-365

tests/aiq_agent/agents/chat_researcher/test_register_helpers.py (1)

18-19: LGTM!

Also applies to: 28-40

tests/aiq_agent/common/test_logging_utils.py (1)

1-20: LGTM!

tests/knowledge_layer_tests/test_summary_store.py (1)

25-32: LGTM!

Also applies to: 218-232

.secrets.baseline (1)

136-136: LGTM!

Also applies to: 354-358

mcp/tests/test_deployment_assets.py (2)

91-98: Hash-based schema assertion is reasonably backed by explicit content checks.

The SHA-256 comparison against _EXPECTED_SQL_HASH could in isolation be "fixed" by simply recomputing the hash after any change, but lines 95-97 also assert specific structural content (mcp_jobs table, index name, migration version rows), which mitigates the rubber-stamp risk. No action needed.


1-155: LGTM!

mcp/Dockerfile (2)

10-96: LGTM!


47-58: 🩺 Stability & Availability

Wrong Dockerfile: the reported uv sync --frozen --extra s3 failure is from deploy/Dockerfile:79, not mcp/Dockerfile; mcp/Dockerfile doesn’t pass --extra s3, and line 79 there is ENV HOME=/home/aiq.

			> Likely an incorrect or invalid review comment.
deploy/compose/docker-compose.mcp.yaml (3)

53-53: 🎯 Functional Correctness | ⚡ Quick win

Inconsistent shell parameter-expansion operator for AIQ_MCP_CORS_ORIGINS.

Every other overridable variable in this service uses ${VAR:-default} (unset-or-empty falls back to default), but this one uses ${VAR-default} (only unset falls back; an explicitly empty value is kept as-is). This is inconsistent with the pattern used for AIQ_MCP_PATH, AIQ_MCP_WORKERS, AIQ_MCP_LOG_LEVEL, AIQ_MCP_ALLOWED_HOSTS, and AIQ_MCP_ALLOWED_ORIGINS on the surrounding lines. If this asymmetry is intentional (e.g., to let users explicitly disable CORS by setting an empty string), it should be commented; otherwise it looks like a typo.

🔧 Proposed fix
-      AIQ_MCP_CORS_ORIGINS: "${AIQ_MCP_CORS_ORIGINS-http://localhost:6274}"
+      AIQ_MCP_CORS_ORIGINS: "${AIQ_MCP_CORS_ORIGINS:-http://localhost:6274}"

17-22: 🔒 Security & Privacy | ⚡ Quick win

Postgres password/checkpoint DB URL has no override mechanism.

Every other configurable value in the aiq-mcp service uses the ${VAR:-default} pattern so operators can override without editing the file, but POSTGRES_PASSWORD and the embedded password in AIQ_CHECKPOINT_DB are hardcoded literals. The comment on lines 18-20 explains why a raw password isn't simply interpolated (percent-encoding of reserved URI characters), which is a fair constraint, but it still means anyone reusing this compose file beyond pure loopback-only local testing must hand-edit the YAML to change the credential rather than setting an env var. Since this is a deploy/** config, consider at least parameterizing the default (e.g., ${AIQ_MCP_POSTGRES_PASSWORD:-local_mcp_password} on both lines) so the override path exists even if percent-encoding correctness is the caller's responsibility.

As per path instructions, deployment/config changes should be reviewed for "secret separation, safe defaults, local-vs-production behavior" and should flag "committed credentials."

Also applies to: 44-46

Source: Path instructions


1-16: LGTM!

Also applies to: 23-43, 47-91

mcp/pyproject.toml (2)

27-38: Version ranges verified as currently valid.

Checked starlette>=1.0,<2 and uvicorn>=0.40,<1 against current PyPI releases (Starlette is at 1.3.x, Uvicorn is at 0.50.x as of mid-2026), so both ranges resolve correctly and don't exceed real published versions. The exact pin on mcp==1.27.2 is also a safe choice given the upstream SDK's own guidance to add a <2 upper bound ahead of the v2.0.0 stable release targeted for 2026-07-28.


1-53: LGTM!

mcp/src/aiq_mcp/__init__.py (1)

1-7: LGTM!

mcp/tests/test_config_and_packaging.py (1)

1-139: LGTM!

mcp/tests/test_imports.py (1)

1-67: LGTM!

mcp/deploy/init-mcp-db.sql (1)

18-54: LGTM!

mcp/deploy/README.md (1)

1-12: LGTM!

mcp/scripts/check_license_inventory.py (1)

297-397: LGTM!

mcp/tests/test_release_checks.py (1)

1-204: LGTM!

mcp/REFERENCE_PARITY.md (1)

1-85: LGTM!

LICENSE-THIRD-PARTY (1)

8-11: LGTM!

.dockerignore (1)

64-71: 🚀 Performance & Scalability

Keep frontends/benchmarks/ in the build context. mcp/Dockerfile copies frontends/benchmarks/freshqa/pyproject.toml and frontends/benchmarks/deepsearch_qa/pyproject.toml, so re-ignoring that directory would break the build.

			> Likely an incorrect or invalid review comment.
mcp/scripts/check_runtime_dependencies.py (1)

17-96: LGTM!

mcp/tests/test_runtime_dependencies.py (1)

1-76: LGTM!

mcp/LICENSE (1)

1-202: LGTM!

.github/workflows/ci.yml (2)

101-165: LGTM!

Also applies to: 208-216, 236-300


217-234: 🩺 Stability & Availability

Drop this comment uv audit --preview-features audit-command,json-output and --ignore-until-fixed are supported by the pinned uv version, and the workflow matches the documented invocation.

			> Likely an incorrect or invalid review comment.
.pre-commit-config.yaml (1)

70-75: LGTM!

pyproject.toml (1)

51-51: LGTM!

Also applies to: 101-101, 158-158, 211-212, 214-218, 227-228, 243-243, 257-257

mcp/tests/test_dependency_compatibility.py (2)

33-90: LGTM!


26-30: 🗄️ Data Integrity & Integration

nvidia-nat is pinned at the workspace level
pyproject.toml already pins nvidia-nat[langchain,async_endpoints,phoenix,mcp]==1.8.0, so the version("nvidia-nat") assertion is consistent with the compatibility baseline.

			> Likely an incorrect or invalid review comment.
mcp/scripts/protocol_smoke.py (2)

70-83: 🩺 Stability & Availability | ⚡ Quick win

Verify the ClientSession contract before relying on this smoke test.

read_timeout_seconds is passed a timedelta, and the stateless-session assertion depends on get_session_id() semantics. If the pinned MCP SDK expects a numeric timeout or reports a client-side session ID for streamable HTTP, this will fail before it exercises the server contract. Please confirm against the version shipped in this repo and adjust the timeout type or assertion if needed.


1-69: LGTM!

Also applies to: 84-143

mcp/SECURITY.md (1)

1-120: LGTM!

README.md (1)

41-41: LGTM!

Also applies to: 244-244, 305-319

docs/source/index.md (1)

76-76: LGTM!

docs/source/integration/index.md (1)

12-12: LGTM!

docs/source/integration/mcp-server.md (1)

1-251: LGTM!

mcp/README.md (1)

1-167: LGTM!

mcp/src/aiq_mcp/job_store.py (2)

121-319: 🔒 Security & Privacy

Static-analysis SQL-injection hints are false positives.

All f-string interpolations here are table/schema identifiers produced by _quote_identifier (regex-validated, Line 352-355) — never raw user input. Actual values (job_id, principal, query, etc.) are always passed as $n bind parameters. No injection risk.

Source: Linters/SAST tools


1-355: LGTM! Schema migration/versioning, poll/heartbeat reconciliation, and TTL sweep semantics look correct and are exercised by the Postgres integration tests.

mcp/src/aiq_mcp/db_url.py (1)

1-21: LGTM!

mcp/src/aiq_mcp/checkpoint_todos.py (1)

1-271: LGTM! Fail-soft error handling, redacted logging of the thread capability id, and the latest-todo CTE query all check out against the accompanying tests.

mcp/tests/test_db_url.py (1)

1-29: LGTM!

mcp/tests/test_job_store.py (1)

1-21: LGTM!

mcp/tests/test_checkpoint_todos.py (1)

1-478: LGTM! Solid coverage of the redaction, fail-soft, and namespace-exclusion contracts that checkpoint_todos.py relies on.

mcp/tests/test_postgres_job_store.py (1)

1-509: LGTM! Thorough integration coverage for reconciliation and multi-instance job handoff semantics.

configs/config_mcp.yml (1)

1-109: LGTM! Matches the shipped-config contract test exactly, and secrets are correctly deferred to env vars.

mcp/src/aiq_mcp/jobs.py (1)

1-343: LGTM!

Also applies to: 350-506

mcp/src/aiq_mcp/workflow_runner.py (2)

1-50: LGTM!

Also applies to: 90-142


51-89: 🎯 Functional Correctness

Confirm load_workflow() doesn’t already own these caches mcp/src/aiq_mcp/workflow_runner.py:51-89 closes checkpointers and pools after AsyncExitStack.aclose(). If NAT teardown already disposes the same shared _checkpointers / _postgres_pools entries, this becomes a double-close on shutdown.

mcp/tests/test_jobs.py (1)

1-906: LGTM! Thorough golden-contract and redaction coverage; consider adding a case for a heartbeat-write failure mid-run once the _heartbeat_job fix (see jobs.py) lands.

mcp/tests/test_workflow_runner.py (1)

1-170: LGTM!

mcp/src/aiq_mcp/server.py (1)

1-330: LGTM!

Also applies to: 396-567

mcp/tests/test_server_runtime.py (1)

1-992: LGTM!

mcp/tests/test_client_session_integration.py (1)

1-415: LGTM!

Also applies to: 435-516

Comment thread .github/workflows/ci.yml Outdated
Comment thread mcp/src/aiq_mcp/jobs.py Outdated
Comment thread mcp/src/aiq_mcp/server.py Outdated
Comment thread mcp/tests/test_client_session_integration.py
Comment thread src/aiq_agent/common/logging_utils.py

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (8)
mcp/src/aiq_mcp/jobs.py (1)

312-372: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Exception during mark_running bypasses the new state-guarded failure update.

If mark_running itself raises (e.g. a transient asyncpg error) rather than returning False, execution falls into the generic except Exception branch, which marks the job failed using from_states=("running",) and runner_id=self._runner_id. But the row is still queued with no runner_id set, so this update() call never matches and silently returns False — the failure is dropped, and the job sits queued (visible to pollers as still running) until the stale-job reconciler eventually times it out, rather than failing immediately.

🛡️ Proposed fix
     async def _run_job(self, job_id: str, query: str) -> None:
         job_id_token = _current_job_id.set(job_id)
         job_ref = log_identifier_ref(job_id)
         heartbeat_task: asyncio.Task | None = None
+        claimed = False
         try:
             claimed = await self._store.mark_running(job_id, self._runner_id)
             if not claimed:
@@
         except Exception as exc:  # noqa: BLE001 - we want to catch everything for jobs
             logger.error("Job %s failed (%s)", job_ref, type(exc).__name__)
             sanitized = _sanitize_error(exc)
             await self._store.update(
                 job_id,
                 state="failed",
                 error=sanitized,
-                from_states=("running",),
-                runner_id=self._runner_id,
+                from_states=("running",) if claimed else ("queued", "running"),
+                runner_id=self._runner_id if claimed else None,
             )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mcp/src/aiq_mcp/jobs.py` around lines 312 - 372, The _run_job flow in jobs.py
drops failures when _store.mark_running raises before the job row is
transitioned to running. Update the exception handling in _run_job so that
failures from mark_running are recorded against the queued state instead of
always using from_states=("running",) and runner_id=self._runner_id; use the job
state/runner context returned by mark_running, or branch the failure update
based on whether claiming succeeded. Keep the existing behavior for the later
run_query path, but ensure the generic except block can persist a failure even
when mark_running never claimed the job.
mcp/src/aiq_mcp/server.py (1)

379-454: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Wrap the remaining MCP tool calls before they escape

  • submit_query only sanitizes jobs.submit(...); wait_for_completion, poll_query, and get_final_report can still propagate raw internal exceptions through the public MCP error path. Wrap them the same way (or factor a generic helper) so anonymous callers never see backend exception text.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mcp/src/aiq_mcp/server.py` around lines 379 - 454, The remaining public MCP
tool paths in `submit_query`, `poll_query`, and `get_final_report` still allow
raw backend exceptions to escape. Update the `MCP` server methods to sanitize
errors consistently by wrapping `jobs.wait_for_completion(...)`,
`self._get_jobs().poll(...)`, and `self._get_jobs().get_final_report(...)` in
the same public error handling used for `jobs.submit(...)`, or factor a shared
helper for `_public_submit_error`-style translation. Ensure anonymous callers
only receive sanitized failures and never backend exception text.
frontends/ui/src/features/chat/store.ts (1)

2911-2922: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Preserve existing file content when merging artifact updates

artifact.update file events emit content: undefined for durable artifacts, so { ...prev, ...file } clears earlier text when a later metadata-only update arrives for the same filename. Merge only defined fields in frontends/ui/src/features/chat/store.ts, frontends/ui/src/features/chat/hooks/use-deep-research.ts, and frontends/ui/src/features/chat/hooks/use-load-job-data.ts.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontends/ui/src/features/chat/store.ts` around lines 2911 - 2922, The deep
research file merge logic is overwriting existing content with undefined fields
from later metadata-only updates. Update the merge behavior in
addDeepResearchFile, use-deep-research, and use-load-job-data so only defined
values from the incoming file are applied, while preserving existing content and
other previously stored fields for the same filename. Use the existing
identifiers addDeepResearchFile, useDeepResearch, and useLoadJobData to locate
the merge points and make the update logic skip undefined properties instead of
spreading them blindly.
src/aiq_agent/agents/deep_researcher/agent.py (1)

184-202: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Add a regression test for the state.files fallback. The current coverage hits result["files"] and the end-to-end /shared/output.md flow, but not the branch where result has no usable "files" key and _extract_final_markdown must read the markdown from the files argument.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/aiq_agent/agents/deep_researcher/agent.py` around lines 184 - 202, Add a
regression test for the state.files fallback in _extract_final_markdown: current
coverage only exercises result["files"] and the end-to-end output path, but not
the branch where result has no usable "files" key and the method must use the
files argument. Create a focused test around
DeepResearcherAgent._extract_final_markdown that passes a result without valid
files and a files dict containing /shared/output.md or /output.md, then assert
the markdown is returned from that fallback path rather than
_salvage_inline_report.

Source: Path instructions

mcp/tests/test_jobs.py (1)

67-173: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate _MemoryJobStore across test modules.

This class is near-identical to _MemoryJobStore in mcp/tests/test_client_session_integration.py. Extracting a shared test double (e.g. into a conftest.py or a _test_doubles.py helper) would avoid the two copies drifting out of sync as JobStore's real contract (guards, TTL, heartbeat semantics) evolves.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mcp/tests/test_jobs.py` around lines 67 - 173, The `_MemoryJobStore` test
double is duplicated across test modules and should be shared to prevent drift
as `JobStore` behavior changes. Move the common implementation behind a reusable
test helper (for example a shared `_test_doubles.py` module or `conftest.py`
fixture) and update the tests to import/use that single `_MemoryJobStore`
definition, keeping the methods like `create`, `mark_running`, `heartbeat`,
`update`, and `mark_stale_running_failed` in one place.
frontends/ui/src/features/layout/components/FileCard.tsx (1)

96-155: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Stale aria-expanded/aria-controls on non-expandable (artifact-only) cards.

The header <Button> still exposes aria-expanded and aria-controls={file-content-${file.id}} even when file.content is absent (now a common case for artifact-only cards with just contentUrl/mimeType). The click handler is a no-op in that case, but the DOM still advertises an expandable/collapsible control to assistive tech, and the referenced region never renders.

♿ Proposed fix
       <Button
         kind="tertiary"
         size="small"
         onClick={() => file.content && setIsExpanded(!isExpanded)}
-        aria-expanded={isExpanded}
-        aria-controls={`file-content-${file.id}`}
+        aria-expanded={file.content ? isExpanded : undefined}
+        aria-controls={file.content ? `file-content-${file.id}` : undefined}
         className="w-full justify-start text-left p-0"
       >
As per path instructions, UI changes should be reviewed for "accessible controls."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontends/ui/src/features/layout/components/FileCard.tsx` around lines 96 -
155, In FileCard, the header Button still advertises expand/collapse behavior
for artifact-only files that have no content, so make the accessibility props
conditional. Update the FileCard button/expansion logic so aria-expanded,
aria-controls, and the click toggle are only applied when file.content exists,
and ensure the expandable region and ChevronDown icon are only rendered for
expandable cards. Use the existing FileCard and file.content checks to keep
non-expandable cards from exposing stale accessible controls.

Source: Path instructions

mcp/tests/test_deployment_assets.py (1)

136-145: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Restore key/cert exclusions in the deployment context guardrail
mcp/tests/test_deployment_assets.py:136-145 no longer asserts **/*.key, **/*.crt, or **/*.pem, and mcp/.dockerignore only excludes **/certs/. That leaves loose private key/cert files unguarded in the Docker build context.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mcp/tests/test_deployment_assets.py` around lines 136 - 145, The deployment
context test is missing coverage for private key and certificate file
exclusions, so update
test_deployment_context_excludes_env_files_and_includes_package_readmes to also
assert the Docker ignore rules for **/*.key, **/*.crt, and **/*.pem. Then adjust
mcp/.dockerignore so these file patterns are explicitly excluded, using the
existing deployment guardrail entries alongside the README allowlist.
scripts/start_e2e.sh (1)

89-104: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Preserve the CLI --port after sourcing deploy/.env. check_env loads deploy/.env after argument parsing, so any local PORT export will override the flag before BACKEND_URL, nat serve --port, and the health check use it. The tracked deploy/.env.example leaves PORT unset, but a user .env can still set it, so re-applying the CLI value after source keeps the explicit flag authoritative.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/start_e2e.sh` around lines 89 - 104, After sourcing deploy/.env in
start_e2e.sh, the CLI --port value can be overwritten by a PORT entry from the
env file, which then affects BACKEND_URL, NEXT_PUBLIC_BACKEND_URL, nat serve
--port, and the health check. Re-apply the parsed port value after the source
block in check_env/startup flow so the explicit command-line flag remains
authoritative, and ensure the PORT variable used by the existing BACKEND_URL
export reflects that restored CLI value.
♻️ Duplicate comments (2)
frontends/ui/src/features/chat/hooks/use-load-job-data.ts (1)

577-582: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Same content-drop defect as use-deep-research.ts and store.ts's addDeepResearchFile.

prev ? { ...prev, ...file } : file overwrites prev.content with undefined when a later artifact.update event for the same filename lacks inline content, contradicting the comment's own intent.

🐛 Proposed fix
             onFileUpdate: (file) => {
               // Merge like the live store: a later metadata-only event must not drop
               // content from an earlier event for the same filename during replay.
               const prev = buffer.files.get(file.filename)
-              buffer.files.set(file.filename, prev ? { ...prev, ...file } : file)
+              const definedUpdates = Object.fromEntries(
+                Object.entries(file).filter(([, value]) => value !== undefined)
+              ) as typeof file
+              buffer.files.set(file.filename, prev ? { ...prev, ...definedUpdates } : file)
             },
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontends/ui/src/features/chat/hooks/use-load-job-data.ts` around lines 577 -
582, The file replay merge in onFileUpdate is still dropping previously captured
content when a later artifact.update arrives without inline content. Update the
merge logic in use-load-job-data to preserve prev.content unless the incoming
file actually provides content, matching the intended behavior already used in
use-deep-research.ts and store.ts’s addDeepResearchFile. Keep the rest of the
file metadata merged as before, but avoid overwriting existing content with
undefined when only metadata changes.
frontends/ui/src/features/chat/hooks/use-deep-research.ts (1)

490-505: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Buffer merge doesn't actually preserve content — same root cause as store.ts's addDeepResearchFile.

{ ...prev, ...file } copies file.content even when it's explicitly undefined (which every non-inline artifact.update event carries per deep-research-client.ts), overwriting prev.content from an earlier replayed event. This defeats the comment's own stated goal during replay/reconnect.

🐛 Proposed fix — filter undefined keys before merging
           onFileUpdate: (file) => {
             if (buf.active) {
               // Merge like the live store (addDeepResearchFile): a later metadata-only
               // event must not drop content from an earlier event for the same filename.
               const prev = buf.files.get(file.filename)
-              buf.files.set(file.filename, prev ? { ...prev, ...file } : file)
+              const definedUpdates = Object.fromEntries(
+                Object.entries(file).filter(([, value]) => value !== undefined)
+              ) as typeof file
+              buf.files.set(file.filename, prev ? { ...prev, ...definedUpdates } : file)
               return
             }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontends/ui/src/features/chat/hooks/use-deep-research.ts` around lines 490 -
505, The replay buffer merge in onFileUpdate still drops previously captured
content because spreading prev and file copies undefined content from later
metadata-only events over earlier data. Update the merge logic used in
use-deep-research.ts so undefined fields are filtered out before combining,
matching the behavior of addDeepResearchFile in store.ts and preserving existing
content during reconnect/replay. Keep the fix localized to the buffered path
inside onFileUpdate, ensuring only defined properties from file overwrite prev.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontends/aiq_api/src/aiq_api/jobs/runner.py`:
- Around line 883-884: The failure path in runner.py is persisting the raw
exception text via job_store.update_status in the job runner, which can leak
secrets or internal hostnames. Update the exception handling around the job
status failure update to store only a sanitized error summary or the exception
class name, following the same pattern used by _teardown_sandbox, and keep the
rest of the context in logs without exposing the raw message.
- Around line 859-866: The cancellation cleanup in runner.py is too narrowly
guarded, so driver-specific or transient job-store errors can still escape and
prevent the job from reaching INTERRUPTED. Update the exception handling around
job_store.get_job and job_store.update_status in the cancellation branch of the
runner logic to catch and swallow/log a broader set of job-store failures, using
the existing job_store and JobStatus.INTERRUPTED flow so cancellation never
leaves the job stranded.

In `@frontends/ui/src/adapters/api/deep-research-client.spec.ts`:
- Around line 5-27: Add a regression test around
createDeepResearchClient/getJobStatus using FakeEventSource that emits an
initial file-artifact event with content and then a later metadata-only
artifact.update for the same filename; assert the stored result keeps the
original content instead of being replaced. This should exercise the merge
behavior that was broken in addDeepResearchFile and the hook buffer paths, so
the test should verify the filename entry retains both metadata and previously
captured content after the second update.

In `@skills/aiq-research/skill-card.md`:
- Around line 33-34: The markdown under the Skill Output section is missing the
required blank line after the heading, causing the MD022 lint failure. Update
the content around the “## Skill Output:” heading in skill-card.md so that there
is an empty line before the “Output Type(s):” line, keeping the existing wording
intact.

---

Outside diff comments:
In `@frontends/ui/src/features/chat/store.ts`:
- Around line 2911-2922: The deep research file merge logic is overwriting
existing content with undefined fields from later metadata-only updates. Update
the merge behavior in addDeepResearchFile, use-deep-research, and
use-load-job-data so only defined values from the incoming file are applied,
while preserving existing content and other previously stored fields for the
same filename. Use the existing identifiers addDeepResearchFile,
useDeepResearch, and useLoadJobData to locate the merge points and make the
update logic skip undefined properties instead of spreading them blindly.

In `@frontends/ui/src/features/layout/components/FileCard.tsx`:
- Around line 96-155: In FileCard, the header Button still advertises
expand/collapse behavior for artifact-only files that have no content, so make
the accessibility props conditional. Update the FileCard button/expansion logic
so aria-expanded, aria-controls, and the click toggle are only applied when
file.content exists, and ensure the expandable region and ChevronDown icon are
only rendered for expandable cards. Use the existing FileCard and file.content
checks to keep non-expandable cards from exposing stale accessible controls.

In `@mcp/src/aiq_mcp/jobs.py`:
- Around line 312-372: The _run_job flow in jobs.py drops failures when
_store.mark_running raises before the job row is transitioned to running. Update
the exception handling in _run_job so that failures from mark_running are
recorded against the queued state instead of always using
from_states=("running",) and runner_id=self._runner_id; use the job state/runner
context returned by mark_running, or branch the failure update based on whether
claiming succeeded. Keep the existing behavior for the later run_query path, but
ensure the generic except block can persist a failure even when mark_running
never claimed the job.

In `@mcp/src/aiq_mcp/server.py`:
- Around line 379-454: The remaining public MCP tool paths in `submit_query`,
`poll_query`, and `get_final_report` still allow raw backend exceptions to
escape. Update the `MCP` server methods to sanitize errors consistently by
wrapping `jobs.wait_for_completion(...)`, `self._get_jobs().poll(...)`, and
`self._get_jobs().get_final_report(...)` in the same public error handling used
for `jobs.submit(...)`, or factor a shared helper for
`_public_submit_error`-style translation. Ensure anonymous callers only receive
sanitized failures and never backend exception text.

In `@mcp/tests/test_deployment_assets.py`:
- Around line 136-145: The deployment context test is missing coverage for
private key and certificate file exclusions, so update
test_deployment_context_excludes_env_files_and_includes_package_readmes to also
assert the Docker ignore rules for **/*.key, **/*.crt, and **/*.pem. Then adjust
mcp/.dockerignore so these file patterns are explicitly excluded, using the
existing deployment guardrail entries alongside the README allowlist.

In `@mcp/tests/test_jobs.py`:
- Around line 67-173: The `_MemoryJobStore` test double is duplicated across
test modules and should be shared to prevent drift as `JobStore` behavior
changes. Move the common implementation behind a reusable test helper (for
example a shared `_test_doubles.py` module or `conftest.py` fixture) and update
the tests to import/use that single `_MemoryJobStore` definition, keeping the
methods like `create`, `mark_running`, `heartbeat`, `update`, and
`mark_stale_running_failed` in one place.

In `@scripts/start_e2e.sh`:
- Around line 89-104: After sourcing deploy/.env in start_e2e.sh, the CLI --port
value can be overwritten by a PORT entry from the env file, which then affects
BACKEND_URL, NEXT_PUBLIC_BACKEND_URL, nat serve --port, and the health check.
Re-apply the parsed port value after the source block in check_env/startup flow
so the explicit command-line flag remains authoritative, and ensure the PORT
variable used by the existing BACKEND_URL export reflects that restored CLI
value.

In `@src/aiq_agent/agents/deep_researcher/agent.py`:
- Around line 184-202: Add a regression test for the state.files fallback in
_extract_final_markdown: current coverage only exercises result["files"] and the
end-to-end output path, but not the branch where result has no usable "files"
key and the method must use the files argument. Create a focused test around
DeepResearcherAgent._extract_final_markdown that passes a result without valid
files and a files dict containing /shared/output.md or /output.md, then assert
the markdown is returned from that fallback path rather than
_salvage_inline_report.

---

Duplicate comments:
In `@frontends/ui/src/features/chat/hooks/use-deep-research.ts`:
- Around line 490-505: The replay buffer merge in onFileUpdate still drops
previously captured content because spreading prev and file copies undefined
content from later metadata-only events over earlier data. Update the merge
logic used in use-deep-research.ts so undefined fields are filtered out before
combining, matching the behavior of addDeepResearchFile in store.ts and
preserving existing content during reconnect/replay. Keep the fix localized to
the buffered path inside onFileUpdate, ensuring only defined properties from
file overwrite prev.

In `@frontends/ui/src/features/chat/hooks/use-load-job-data.ts`:
- Around line 577-582: The file replay merge in onFileUpdate is still dropping
previously captured content when a later artifact.update arrives without inline
content. Update the merge logic in use-load-job-data to preserve prev.content
unless the incoming file actually provides content, matching the intended
behavior already used in use-deep-research.ts and store.ts’s
addDeepResearchFile. Keep the rest of the file metadata merged as before, but
avoid overwriting existing content with undefined when only metadata changes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: d6f875fe-2cc7-4d87-ac22-6dbd26ae5a84

📥 Commits

Reviewing files that changed from the base of the PR and between 006ed46 and afc41be.

⛔ Files ignored due to path filters (1)
  • skills/aiq-research/skill.oms.sig is excluded by !skills/**/skill.oms.sig
📒 Files selected for processing (59)
  • .dockerignore
  • deploy/helm/deployment-k8s/Chart.yaml
  • deploy/helm/deployment-k8s/charts/aiq-0.0.4.tgz
  • deploy/helm/deployment-k8s/charts/aiq-0.0.5.tgz
  • deploy/helm/helm-charts-k8s/aiq/Chart.yaml
  • deploy/helm/helm-charts-k8s/aiq/templates/_helpers.tpl
  • deploy/helm/helm-charts-k8s/aiq/templates/namespace.yaml
  • deploy/helm/helm-charts-k8s/aiq/values.yaml
  • docs/source/architecture/agents/sandbox.md
  • frontends/aiq_api/README.md
  • frontends/aiq_api/src/aiq_api/jobs/runner.py
  • frontends/aiq_api/src/aiq_api/jobs/telemetry.py
  • frontends/ui/src/adapters/api/deep-research-client.spec.ts
  • frontends/ui/src/adapters/api/deep-research-client.ts
  • frontends/ui/src/adapters/api/index.ts
  • frontends/ui/src/features/chat/hooks/use-deep-research.spec.ts
  • frontends/ui/src/features/chat/hooks/use-deep-research.ts
  • frontends/ui/src/features/chat/hooks/use-load-job-data.ts
  • frontends/ui/src/features/chat/store.ts
  • frontends/ui/src/features/chat/types.ts
  • frontends/ui/src/features/layout/components/AgentsTab.spec.tsx
  • frontends/ui/src/features/layout/components/AgentsTab.tsx
  • frontends/ui/src/features/layout/components/FileCard.spec.tsx
  • frontends/ui/src/features/layout/components/FileCard.tsx
  • frontends/ui/src/pages/api/generate-pdf.ts
  • frontends/ui/src/shared/components/MarkdownRenderer/MarkdownRenderer.tsx
  • frontends/ui/src/shared/components/MarkdownRenderer/index.ts
  • frontends/ui/src/shared/utils/artifact-url.spec.ts
  • frontends/ui/src/shared/utils/artifact-url.ts
  • mcp/src/aiq_mcp/job_store.py
  • mcp/src/aiq_mcp/jobs.py
  • mcp/src/aiq_mcp/server.py
  • mcp/tests/test_client_session_integration.py
  • mcp/tests/test_deployment_assets.py
  • mcp/tests/test_jobs.py
  • mcp/tests/test_postgres_job_store.py
  • mcp/tests/test_server_runtime.py
  • scripts/start_e2e.sh
  • skills/aiq-research/BENCHMARK.md
  • skills/aiq-research/SKILL.md
  • skills/aiq-research/scripts/aiq.py
  • skills/aiq-research/skill-card.md
  • src/aiq_agent/agents/deep_researcher/agent.py
  • src/aiq_agent/agents/deep_researcher/custom_middleware.py
  • src/aiq_agent/agents/deep_researcher/deepagents_runtime.py
  • src/aiq_agent/agents/deep_researcher/factory.py
  • src/aiq_agent/agents/deep_researcher/sandbox/README.md
  • src/aiq_agent/agents/deep_researcher/sandbox/artifacts/manager.py
  • src/aiq_agent/agents/deep_researcher/sandbox/artifacts/models.py
  • src/aiq_agent/agents/deep_researcher/sandbox/base.py
  • src/aiq_agent/agents/deep_researcher/tools/research.py
  • tests/aiq_agent/agents/deep_researcher/sandbox/test_artifacts.py
  • tests/aiq_agent/agents/deep_researcher/test_agent.py
  • tests/aiq_agent/agents/deep_researcher/test_custom_middleware.py
  • tests/aiq_agent/agents/deep_researcher/test_deepagents_runtime.py
  • tests/aiq_agent/agents/deep_researcher/test_factory.py
  • tests/aiq_agent/jobs/test_runner.py
  • tests/aiq_agent/jobs/test_telemetry.py
  • tests/deploy/test_helm_deployment_k8s.py
💤 Files with no reviewable changes (1)
  • .dockerignore
📜 Review details
⏰ Context from checks skipped due to timeout. (3)
  • GitHub Check: UI Unit Tests
  • GitHub Check: Script Validation
  • GitHub Check: Pytest and Coverage
⚠️ CI failures not shown inline (3)

GitHub Actions: Skills Eval / Run Harbor skill eval: fix(mcp): harden public job failure handling

Conclusion: failure

View job details

##[group]Run set -a
 �[36;1mset -a�[0m
 �[36;1m# shellcheck disable=SC1090�[0m
 �[36;1msource "$RUNNER_ENV_FILE"�[0m
 �[36;1mset +a�[0m
 �[36;1m# Mirror local recipe: build from source, tag with run id so�[0m
 �[36;1m# concurrent runs (if any) don't collide.�[0m
 �[36;1mexport BACKEND_IMAGE="aiq-agent:ci-28987905264"�[0m
 �[36;1mdocker compose --env-file ../.env -f docker-compose.yaml up -d --build aiq-agent postgres�[0m
 shell: /usr/bin/bash --noprofile --norc -e -o pipefail {0}
 env:
   RUNNER_ENV_FILE: /home/ubuntu/aiq-eval/.env
   pythonLocation: /home/ubuntu/actions-runner/_work/_tool/Python/3.13.13/x64
   PKG_CONFIG_PATH: /home/ubuntu/actions-runner/_work/_tool/Python/3.13.13/x64/lib/pkgconfig
   Python_ROOT_DIR: /home/ubuntu/actions-runner/_work/_tool/Python/3.13.13/x64
   Python2_ROOT_DIR: /home/ubuntu/actions-runner/_work/_tool/Python/3.13.13/x64
   Python3_ROOT_DIR: /home/ubuntu/actions-runner/_work/_tool/Python/3.13.13/x64
   LD_LIBRARY_PATH: /home/ubuntu/actions-runner/_work/_tool/Python/3.13.13/x64/lib
   UV_CACHE_DIR: /home/ubuntu/actions-runner/_work/_temp/setup-uv-cache
 ##[endgroup]
  Image aiq-agent:ci-28987905264 Building
 `#1` [internal] load local bake definitions
 `#1` reading from stdin 583B done
 `#1` DONE 0.0s
 `#2` [internal] load build definition from Dockerfile
 `#2` transferring dockerfile: 5.60kB done
 `#2` DONE 0.0s
 `#3` [internal] load metadata for nvcr.io/nvidia/base/ubuntu:noble-20260217
 `#3` ...
 `#4` [internal] load metadata for nvcr.io/nvidia/distroless/python:3.13-v4.0.5
 `#4` DONE 0.3s
 `#3` [internal] load metadata for nvcr.io/nvidia/base/ubuntu:noble-20260217
 `#3` DONE 0.4s
 `#5` [internal] load .dockerignore
 `#5` transferring context: 1.68kB done
 `#5` DONE 0.0s
 `#6` [dev 1/4] FROM nvcr.io/nvidia/distroless/python:3.13-v4.0.5@sha256:***REDACTED***
 `#6` resolve nvcr.io/nvidia/distroless/python:3.13-v4.0.5@sha256:***REDACTED*** 0.0s done
 `#6` DONE 0.0s
 `#7` [builder  1/17] FROM nvcr.io/nvidia/base/ubuntu:noble-20260217@sha256:***REDACTED***
 `#7` resolve ...

GitHub Actions: Skills Eval / Run Harbor skill eval: fix(mcp): harden public job failure handling

Conclusion: failure

View job details

##[group]Run if [ ! -r "$RUNNER_ENV_FILE" ]; then
 �[36;1mif [ ! -r "$RUNNER_ENV_FILE" ]; then�[0m
 �[36;1m  echo "::error::Runner credential file missing or unreadable at $RUNNER_ENV_FILE"�[0m

GitHub Actions: Skills Eval / 0_Run Harbor skill eval.txt: fix(mcp): harden public job failure handling

Conclusion: failure

View job details

##[group]Run if [ ! -r "$RUNNER_ENV_FILE" ]; then
 �[36;1mif [ ! -r "$RUNNER_ENV_FILE" ]; then�[0m
 �[36;1m  echo "::error::Runner credential file missing or unreadable at $RUNNER_ENV_FILE"�[0m
🧰 Additional context used
📓 Path-based instructions (14)
**

⚙️ CodeRabbit configuration file

**:

AI-Q Agent Guidance

Repository-global instructions for coding agents and for humans reviewing
agent-authored changes. These rules apply to every task in this repository.
Task-specific runbooks live in .agents/skills/ — load the
relevant skill before starting a workflow it covers.

Project overview

AI-Q is an NVIDIA AI Blueprint: an enterprise research agent built on the
NeMo Agent Toolkit (NAT). The deployed product is a research blueprint, not
a general skill runtime. New retrieval sources and tools are NAT functions;
agent behavior is driven by workflow YAML, Jinja2 prompts, and a data-source
registry — not by hard-coded logic.

Primary boundaries:

  • Backend Python package: src/aiq_agent/.
  • Data-source and tool packages: sources/ (each is its own package).
  • Frontends and tooling: frontends/ (web UI in frontends/ui/, eval harnesses
    in frontends/benchmarks/).
  • Configs, deployment, docs: configs/, deploy/, docs/.

Stay inside this repository. If your workspace also contains adjacent repos
(for example a sibling NeMo-Relay checkout), do not edit them as part of an AI-Q
change. Treat sources/* as independent packages: prefer the smallest change
scoped to the package you are touching.

Repository structure

Path Purpose
src/aiq_agent/ Backend agent, FastAPI extensions, auth, observability, knowledge
sources/ Data-source / tool packages (e.g. tavily_web_search, google_scholar_paper_search)
configs/ Workflow YAML configs (e.g. config_cli_default.yml)
frontends/ui/ Next.js / React / TypeScript / Tailwind / KUI web UI
frontends/benchmarks/ Eval harnesses: freshqa, deepsearch_qa, deepresearch_bench
deploy/ Docker Compose and Helm/Kubernetes assets; deploy/.env for secrets
docs/source/ ...

Files:

  • deploy/helm/helm-charts-k8s/aiq/Chart.yaml
  • deploy/helm/helm-charts-k8s/aiq/templates/namespace.yaml
  • frontends/ui/src/features/layout/components/AgentsTab.tsx
  • frontends/ui/src/adapters/api/index.ts
  • frontends/ui/src/pages/api/generate-pdf.ts
  • deploy/helm/helm-charts-k8s/aiq/templates/_helpers.tpl
  • skills/aiq-research/BENCHMARK.md
  • deploy/helm/helm-charts-k8s/aiq/values.yaml
  • frontends/ui/src/features/layout/components/FileCard.spec.tsx
  • frontends/ui/src/features/chat/store.ts
  • frontends/ui/src/features/layout/components/AgentsTab.spec.tsx
  • docs/source/architecture/agents/sandbox.md
  • frontends/aiq_api/README.md
  • frontends/ui/src/shared/components/MarkdownRenderer/MarkdownRenderer.tsx
  • src/aiq_agent/agents/deep_researcher/sandbox/base.py
  • tests/aiq_agent/agents/deep_researcher/test_factory.py
  • frontends/ui/src/shared/components/MarkdownRenderer/index.ts
  • deploy/helm/deployment-k8s/Chart.yaml
  • frontends/aiq_api/src/aiq_api/jobs/telemetry.py
  • frontends/ui/src/adapters/api/deep-research-client.spec.ts
  • tests/aiq_agent/jobs/test_runner.py
  • src/aiq_agent/agents/deep_researcher/tools/research.py
  • src/aiq_agent/agents/deep_researcher/agent.py
  • skills/aiq-research/SKILL.md
  • src/aiq_agent/agents/deep_researcher/sandbox/artifacts/models.py
  • frontends/ui/src/features/chat/hooks/use-deep-research.spec.ts
  • frontends/ui/src/features/chat/hooks/use-deep-research.ts
  • src/aiq_agent/agents/deep_researcher/custom_middleware.py
  • src/aiq_agent/agents/deep_researcher/sandbox/artifacts/manager.py
  • scripts/start_e2e.sh
  • frontends/ui/src/features/chat/hooks/use-load-job-data.ts
  • frontends/ui/src/features/chat/types.ts
  • tests/aiq_agent/agents/deep_researcher/test_deepagents_runtime.py
  • skills/aiq-research/skill-card.md
  • src/aiq_agent/agents/deep_researcher/factory.py
  • src/aiq_agent/agents/deep_researcher/deepagents_runtime.py
  • skills/aiq-research/scripts/aiq.py
  • tests/aiq_agent/agents/deep_researcher/sandbox/test_artifacts.py
  • frontends/ui/src/features/layout/components/FileCard.tsx
  • tests/aiq_agent/agents/deep_researcher/test_agent.py
  • mcp/tests/test_deployment_assets.py
  • tests/aiq_agent/jobs/test_telemetry.py
  • tests/deploy/test_helm_deployment_k8s.py
  • frontends/ui/src/adapters/api/deep-research-client.ts
  • tests/aiq_agent/agents/deep_researcher/test_custom_middleware.py
  • src/aiq_agent/agents/deep_researcher/sandbox/README.md
  • mcp/tests/test_client_session_integration.py
  • frontends/aiq_api/src/aiq_api/jobs/runner.py
  • mcp/src/aiq_mcp/jobs.py
  • mcp/src/aiq_mcp/server.py
  • mcp/src/aiq_mcp/job_store.py
  • mcp/tests/test_server_runtime.py
  • mcp/tests/test_jobs.py
  • mcp/tests/test_postgres_job_store.py
{deploy/**,configs/**}

⚙️ CodeRabbit configuration file

{deploy/**,configs/**}: Review deployment and config changes for secret separation, safe defaults, local-vs-production behavior, Helm and
Docker portability, and documentation parity. Flag committed credentials, environment-specific NVIDIA internals in
public defaults, and changes that make examples diverge from CI-tested paths.

Files:

  • deploy/helm/helm-charts-k8s/aiq/Chart.yaml
  • deploy/helm/helm-charts-k8s/aiq/templates/namespace.yaml
  • deploy/helm/helm-charts-k8s/aiq/templates/_helpers.tpl
  • deploy/helm/helm-charts-k8s/aiq/values.yaml
  • deploy/helm/deployment-k8s/Chart.yaml
frontends/ui/**/*.{js,ts,jsx,tsx,vue}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Run npm lint, type-check, and build validation for UI changes in frontends/ui

Files:

  • frontends/ui/src/features/layout/components/AgentsTab.tsx
  • frontends/ui/src/adapters/api/index.ts
  • frontends/ui/src/pages/api/generate-pdf.ts
  • frontends/ui/src/features/layout/components/FileCard.spec.tsx
  • frontends/ui/src/features/chat/store.ts
  • frontends/ui/src/features/layout/components/AgentsTab.spec.tsx
  • frontends/ui/src/shared/components/MarkdownRenderer/MarkdownRenderer.tsx
  • frontends/ui/src/shared/components/MarkdownRenderer/index.ts
  • frontends/ui/src/adapters/api/deep-research-client.spec.ts
  • frontends/ui/src/features/chat/hooks/use-deep-research.spec.ts
  • frontends/ui/src/features/chat/hooks/use-deep-research.ts
  • frontends/ui/src/features/chat/hooks/use-load-job-data.ts
  • frontends/ui/src/features/chat/types.ts
  • frontends/ui/src/features/layout/components/FileCard.tsx
  • frontends/ui/src/adapters/api/deep-research-client.ts
frontends/ui/**/*.{ts,tsx,jsx,js}

📄 CodeRabbit inference engine (AGENTS.md)

frontends/ui/**/*.{ts,tsx,jsx,js}: The UI is built with Next.js / React / TypeScript / Tailwind with KUI components; reuse existing KUI components and visual patterns rather than introducing new ones
Validate UI-affecting changes with npm run lint, npm run type-check, and npm run test:ci, and include a screenshot for visible changes

Files:

  • frontends/ui/src/features/layout/components/AgentsTab.tsx
  • frontends/ui/src/adapters/api/index.ts
  • frontends/ui/src/pages/api/generate-pdf.ts
  • frontends/ui/src/features/layout/components/FileCard.spec.tsx
  • frontends/ui/src/features/chat/store.ts
  • frontends/ui/src/features/layout/components/AgentsTab.spec.tsx
  • frontends/ui/src/shared/components/MarkdownRenderer/MarkdownRenderer.tsx
  • frontends/ui/src/shared/components/MarkdownRenderer/index.ts
  • frontends/ui/src/adapters/api/deep-research-client.spec.ts
  • frontends/ui/src/features/chat/hooks/use-deep-research.spec.ts
  • frontends/ui/src/features/chat/hooks/use-deep-research.ts
  • frontends/ui/src/features/chat/hooks/use-load-job-data.ts
  • frontends/ui/src/features/chat/types.ts
  • frontends/ui/src/features/layout/components/FileCard.tsx
  • frontends/ui/src/adapters/api/deep-research-client.ts
frontends/ui/**/*

⚙️ CodeRabbit configuration file

frontends/ui/**/*: Review UI changes for strict TypeScript behavior, API contract alignment, auth/session handling, accessible controls,
resilient loading and error states, and report/chat state consistency. Prefer existing UI patterns and require tests
for changed user-visible workflows.

Files:

  • frontends/ui/src/features/layout/components/AgentsTab.tsx
  • frontends/ui/src/adapters/api/index.ts
  • frontends/ui/src/pages/api/generate-pdf.ts
  • frontends/ui/src/features/layout/components/FileCard.spec.tsx
  • frontends/ui/src/features/chat/store.ts
  • frontends/ui/src/features/layout/components/AgentsTab.spec.tsx
  • frontends/ui/src/shared/components/MarkdownRenderer/MarkdownRenderer.tsx
  • frontends/ui/src/shared/components/MarkdownRenderer/index.ts
  • frontends/ui/src/adapters/api/deep-research-client.spec.ts
  • frontends/ui/src/features/chat/hooks/use-deep-research.spec.ts
  • frontends/ui/src/features/chat/hooks/use-deep-research.ts
  • frontends/ui/src/features/chat/hooks/use-load-job-data.ts
  • frontends/ui/src/features/chat/types.ts
  • frontends/ui/src/features/layout/components/FileCard.tsx
  • frontends/ui/src/adapters/api/deep-research-client.ts
skills/aiq-research/**

⚙️ CodeRabbit configuration file

skills/aiq-research/**: ---
name: aiq-research
description: |
Use when asked to run deep research or AI-Q research through a reachable NVIDIA AI-Q Blueprint backend.
license: Apache-2.0
permissions:
env:
- AIQ_SERVER_URL
network:
- http://localhost:8000
compatibility: |
Designed for Claude Code, OpenCode, Codex, and Agent Skills-compatible tools. Requires Python 3.11+ and network
access to a running local AI-Q Blueprint server at http://localhost:8000 by default. Non-local backends must be
explicitly trusted by the user and granted by the host tool outside this public skill.
metadata:
version: "2.1.0"
author: "NVIDIA AI-Q Blueprint Team aiq-blueprint@nvidia.com"
github-url: "https://github.com/NVIDIA-AI-Blueprints/aiq"
tags:
- nvidia
- aiq
- blueprint
- deep-research
- research-agents
- agent-skills
languages:
- python
- bash
domain: "research-agents"
allowed-tools: Read Bash

AIQ Research Skill

Purpose

Use this skill to call a locally running NVIDIA AI-Q Blueprint server through the helper script at
scripts/aiq.py.

Use this skill for research-shaped requests, including:

  • "deep research on ..."
  • "AIQ research ..."
  • "research ..."
  • "use AI-Q to answer ..."
  • "ask AI-Q about ..."

Do not use this skill for install, deploy, start, stop, UI, CLI, Docker, Helm, or troubleshooting requests. Those
belong to aiq-deploy.

Prerequisites

Users need:

  • Python 3.11+ available as python3.
  • A reachable local or self-hosted AI-Q Blueprint backend.
  • AIQ_SERVER_URL set when the backend is not running at http://localhost:8000; non-local values must be trusted by
    the user before any query is sent.
  • A backend configured with authentication disabled for this public helper, or a separate authenticated AI-Q skill for
    authenticated environments.
  • Network access from the local machine to the AI-Q backend URL.
  • Credentials configured in the backend environment, not in this skill. Thi...

Files:

  • skills/aiq-research/BENCHMARK.md
  • skills/aiq-research/SKILL.md
  • skills/aiq-research/skill-card.md
  • skills/aiq-research/scripts/aiq.py
{skills/**,.agents/skills/**,.claude/skills/**,.github/skill-eval/**}

⚙️ CodeRabbit configuration file

{skills/**,.agents/skills/**,.claude/skills/**,.github/skill-eval/**}: Review Agent Skill and skill-eval changes for valid skill metadata, deterministic eval specs, safe handling of
credentials, and clear generated-output boundaries. Do not flag SKILL.md files for missing SPDX headers when the
entrypoint intentionally starts with YAML frontmatter.

Files:

  • skills/aiq-research/BENCHMARK.md
  • skills/aiq-research/SKILL.md
  • skills/aiq-research/skill-card.md
  • skills/aiq-research/scripts/aiq.py
docs/source/**/*

📄 CodeRabbit inference engine (AGENTS.md)

Update the docs under docs/source/ when behavior, configuration, or workflows change

Files:

  • docs/source/architecture/agents/sandbox.md
{docs/**,README.md,CONTRIBUTING.md,SECURITY.md,CODE-OF-CONDUCT.md}

⚙️ CodeRabbit configuration file

{docs/**,README.md,CONTRIBUTING.md,SECURITY.md,CODE-OF-CONDUCT.md}: Review documentation for command accuracy, branch-name consistency, current CI and copy-pr-bot behavior, public
vs internal boundary clarity, stale examples, and links that no longer match the repository layout.

Files:

  • docs/source/architecture/agents/sandbox.md
**/*.py

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Run ruff check and ruff format validation for Python code changes

**/*.py: Python code must be linted and formatted with Ruff using line length 120, target Python 3.11, rule sets E,F,W,I,PL,UP, and isort force-single-line configuration
Never commit secrets, tokens, or environment-specific hostnames; use environment variables and SecretStr instead, resolving API keys at runtime
Never print or log secret values, including in tool output or error messages
Missing-secret paths must degrade gracefully (stub/skip), not crash or leak
Do not hand-reformat unrelated code when making changes; match the existing import and formatting style

Files:

  • src/aiq_agent/agents/deep_researcher/sandbox/base.py
  • tests/aiq_agent/agents/deep_researcher/test_factory.py
  • frontends/aiq_api/src/aiq_api/jobs/telemetry.py
  • tests/aiq_agent/jobs/test_runner.py
  • src/aiq_agent/agents/deep_researcher/tools/research.py
  • src/aiq_agent/agents/deep_researcher/agent.py
  • src/aiq_agent/agents/deep_researcher/sandbox/artifacts/models.py
  • src/aiq_agent/agents/deep_researcher/custom_middleware.py
  • src/aiq_agent/agents/deep_researcher/sandbox/artifacts/manager.py
  • tests/aiq_agent/agents/deep_researcher/test_deepagents_runtime.py
  • src/aiq_agent/agents/deep_researcher/factory.py
  • src/aiq_agent/agents/deep_researcher/deepagents_runtime.py
  • skills/aiq-research/scripts/aiq.py
  • tests/aiq_agent/agents/deep_researcher/sandbox/test_artifacts.py
  • tests/aiq_agent/agents/deep_researcher/test_agent.py
  • mcp/tests/test_deployment_assets.py
  • tests/aiq_agent/jobs/test_telemetry.py
  • tests/deploy/test_helm_deployment_k8s.py
  • tests/aiq_agent/agents/deep_researcher/test_custom_middleware.py
  • mcp/tests/test_client_session_integration.py
  • frontends/aiq_api/src/aiq_api/jobs/runner.py
  • mcp/src/aiq_mcp/jobs.py
  • mcp/src/aiq_mcp/server.py
  • mcp/src/aiq_mcp/job_store.py
  • mcp/tests/test_server_runtime.py
  • mcp/tests/test_jobs.py
  • mcp/tests/test_postgres_job_store.py
src/aiq_agent/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

src/aiq_agent/**/*.py: Respect authenticated data sources by honoring requires_auth, per-user token pass-through, and backend token validators; apply owner guardrails before loading protected report or artifact context into an agent
Do not weaken or bypass AuthMiddleware, validators, or auth gating without a prior design discussion

Files:

  • src/aiq_agent/agents/deep_researcher/sandbox/base.py
  • src/aiq_agent/agents/deep_researcher/tools/research.py
  • src/aiq_agent/agents/deep_researcher/agent.py
  • src/aiq_agent/agents/deep_researcher/sandbox/artifacts/models.py
  • src/aiq_agent/agents/deep_researcher/custom_middleware.py
  • src/aiq_agent/agents/deep_researcher/sandbox/artifacts/manager.py
  • src/aiq_agent/agents/deep_researcher/factory.py
  • src/aiq_agent/agents/deep_researcher/deepagents_runtime.py
src/aiq_agent/agents/**/*

⚙️ CodeRabbit configuration file

src/aiq_agent/agents/**/*: Review agent changes for research workflow correctness, graph state transitions, prompt/tool contracts,
HITL behavior, and failure handling. Flag changes that weaken source attribution, report generation,
async cancellation, checkpointing, or data-source selection without focused tests and docs.

Files:

  • src/aiq_agent/agents/deep_researcher/sandbox/base.py
  • src/aiq_agent/agents/deep_researcher/tools/research.py
  • src/aiq_agent/agents/deep_researcher/agent.py
  • src/aiq_agent/agents/deep_researcher/sandbox/artifacts/models.py
  • src/aiq_agent/agents/deep_researcher/custom_middleware.py
  • src/aiq_agent/agents/deep_researcher/sandbox/artifacts/manager.py
  • src/aiq_agent/agents/deep_researcher/factory.py
  • src/aiq_agent/agents/deep_researcher/deepagents_runtime.py
  • src/aiq_agent/agents/deep_researcher/sandbox/README.md
**/*test*.py

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Run pytest for all behavior changes in Python code

Files:

  • tests/aiq_agent/agents/deep_researcher/test_factory.py
  • tests/aiq_agent/jobs/test_runner.py
  • tests/aiq_agent/agents/deep_researcher/test_deepagents_runtime.py
  • tests/aiq_agent/agents/deep_researcher/sandbox/test_artifacts.py
  • tests/aiq_agent/agents/deep_researcher/test_agent.py
  • mcp/tests/test_deployment_assets.py
  • tests/aiq_agent/jobs/test_telemetry.py
  • tests/deploy/test_helm_deployment_k8s.py
  • tests/aiq_agent/agents/deep_researcher/test_custom_middleware.py
  • mcp/tests/test_client_session_integration.py
  • mcp/tests/test_server_runtime.py
  • mcp/tests/test_jobs.py
  • mcp/tests/test_postgres_job_store.py
{src/aiq_agent/fastapi_extensions/**,frontends/aiq_api/src/aiq_api/**}

⚙️ CodeRabbit configuration file

{src/aiq_agent/fastapi_extensions/**,frontends/aiq_api/src/aiq_api/**}: Treat API, auth, and job-runner changes as externally visible contracts. Check authorization boundaries,
request tracing, async job lifecycle, websocket reconnect behavior, error responses, and cross-user data isolation.
Require tests for route behavior, access decisions, and job state transitions when those surfaces change.

Files:

  • frontends/aiq_api/src/aiq_api/jobs/telemetry.py
  • frontends/aiq_api/src/aiq_api/jobs/runner.py
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T01:37:03.708Z
Learning: Use this skill only for research-shaped requests that need a reachable NVIDIA AI-Q Blueprint backend via `scripts/aiq.py`; do not use it for install, deploy, start, stop, UI, CLI, Docker, Helm, or troubleshooting requests, which belong to `aiq-deploy`.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T01:37:03.708Z
Learning: Before sending any user query to AI-Q, resolve the backend URL, run `health`, state the exact endpoint to the user, and only proceed with non-local URLs after explicit trust confirmation in the conversation.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T01:37:03.708Z
Learning: If no backend is reachable, ask for an AI-Q backend URL or hand off to `aiq-deploy`; if the backend returns `401` or `403`, stop and explain that this public skill does not manage authentication.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T01:37:03.708Z
Learning: Do not send credentials, cookies, bearer tokens, or secret values in AI-Q query text or follow-up query text.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T01:37:03.708Z
Learning: When AI-Q returns a deep-research job ID, poll asynchronous jobs with `research_poll`, tell the user deep research is running in the background, and do not retry failed jobs automatically.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T01:37:03.708Z
Learning: If polling is interrupted, resume using `status`, `report`, or `research_poll`; use `status` to inspect job state and artifacts, `report` for finished jobs, and `research_poll` to continue waiting.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T01:37:03.708Z
Learning: Present returned reports with citations and source URLs intact; do not truncate them.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T01:37:03.708Z
Learning: After presenting a report, answer follow-up questions from the existing report directly when possible; otherwise send a fresh query that carries prior context, and use the same backend/auth/polling flow.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T01:37:03.708Z
Learning: For a redo, rerun research with a refined query and appropriate agent type, treating it as a new job and restating the target endpoint before sending it.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T01:37:03.708Z
Learning: Respect the skill’s version compatibility rules: the Blueprint major version must match the skill major version, the Blueprint minor version must be equal or greater, and patch version may vary.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T01:37:03.708Z
Learning: If the backend is reachable but `/chat` or async job routes fail, report that the backend is reachable but not compatible with this public research flow; do not fabricate answers.
📚 Learning: 2026-07-06T23:55:42.908Z
Learnt from: cdgamarose-nv
Repo: NVIDIA-AI-Blueprints/aiq PR: 311
File: src/aiq_agent/agents/deep_researcher/prompts/orchestrator.j2:74-81
Timestamp: 2026-07-06T23:55:42.908Z
Learning: In agent test files (e.g., tests/aiq_agent/agents/*/test_agent.py), avoid brittle assertions that match exact substrings from prompt template files (such as *.j2 prompt wording). Prompt wording can change frequently, so instead assert structural/behavioral properties (e.g., that the prompt builder is called, that required sections/fields are present via stable markers, that the model output/agent behavior conforms to an expected schema, or that key actions are taken) rather than matching literal prompt text.

Applied to files:

  • tests/aiq_agent/agents/deep_researcher/test_agent.py
🪛 ast-grep (0.44.1)
tests/deploy/test_helm_deployment_k8s.py

[error] 26-31: Command coming from incoming request
Context: subprocess.run(
["helm", "template", "aiq", str(CHART_PATH), "-n", namespace, *extra_args],
check=True,
capture_output=True,
text=True,
)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(subprocess-from-request)

🪛 LanguageTool
skills/aiq-research/skill-card.md

[style] ~12-~12: Consider a different adjective to strengthen your wording.
Context: ... and engineers use this skill to submit deep research queries to a running NVIDIA AI...

(DEEP_PROFOUND)


[style] ~37-~37: Consider a different adjective to strengthen your wording.
Context: ...Output:** [Asynchronous job polling for deep research; artifact download for charts ...

(DEEP_PROFOUND)

🪛 markdownlint-cli2 (0.22.1)
skills/aiq-research/skill-card.md

[warning] 33-33: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)

🪛 OpenGrep (1.23.0)
mcp/src/aiq_mcp/job_store.py

[ERROR] 142-154: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)


[ERROR] 202-205: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)

Comment thread frontends/aiq_api/src/aiq_api/jobs/runner.py
Comment thread frontends/aiq_api/src/aiq_api/jobs/runner.py Outdated
Comment thread frontends/ui/src/adapters/api/deep-research-client.spec.ts
Comment thread skills/aiq-research/skill-card.md

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
mcp/Dockerfile (1)

53-54: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consolidate the inline version-assertion one-liner into the existing check script.

Line 54 hardcodes version('mcp') == '1.27.2' and version('nvidia-nat-core') == '1.8.0' inline in a long, hard-to-diff Python one-liner, duplicating information that already lives in mcp/pyproject.toml/mcp/uv.lock. A dedicated check_runtime_dependencies.py script already exists one line above (line 53) for this exact purpose — moving the import/version/entry-point assertions there would keep the release "canary" logic testable and reviewable outside the Dockerfile, instead of as an unwrapped shell string.

♻️ Proposed consolidation
-RUN /opt/venv/bin/python mcp/scripts/check_runtime_dependencies.py \
-    && /opt/venv/bin/python -c "import importlib; from importlib.metadata import entry_points, version; [importlib.import_module(name) for name in ('aiq_mcp', 'aiq_mcp.server', 'aiq_mcp.jobs', 'aiq_mcp.job_store', 'aiq_mcp.workflow_runner', 'aiq_agent.common', 'tavily_web_search', 'knowledge_layer', 'asyncpg')]; assert version('mcp') == '1.27.2'; assert version('nvidia-nat-core') == '1.8.0'; assert any(ep.name == 'tavily_web_search' for ep in entry_points(group='nat.plugins')); print('AI-Q MCP runtime verified')"
+RUN /opt/venv/bin/python mcp/scripts/check_runtime_dependencies.py

Move the imports, version(...) == assertions, and entry-point check into check_runtime_dependencies.py so version drift shows up as a clean diff in a reviewable Python file rather than a one-line shell string.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mcp/Dockerfile` around lines 53 - 54, The Dockerfile’s long Python one-liner
duplicates runtime checks that should live in the existing
check_runtime_dependencies.py script. Move the import/module validation, version
assertions for mcp and nvidia-nat-core, and the nat.plugins entry-point check
into check_runtime_dependencies.py, then keep the Dockerfile RUN step limited to
invoking that script and the final verification print.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@mcp/Dockerfile`:
- Around line 53-54: The Dockerfile’s long Python one-liner duplicates runtime
checks that should live in the existing check_runtime_dependencies.py script.
Move the import/module validation, version assertions for mcp and
nvidia-nat-core, and the nat.plugins entry-point check into
check_runtime_dependencies.py, then keep the Dockerfile RUN step limited to
invoking that script and the final verification print.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 7ab0f028-d2f3-4e26-b5d2-e4713290cb60

📥 Commits

Reviewing files that changed from the base of the PR and between afc41be and 56c4cae.

⛔ Files ignored due to path filters (2)
  • mcp/uv.lock is excluded by !**/*.lock
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (32)
  • .agents/skills/aiq-maintain-ci/SKILL.md
  • .agents/skills/aiq-maintain-ci/references/workflows-and-hooks.md
  • .agents/skills/aiq-release-qa/SKILL.md
  • .agents/skills/aiq-release-qa/references/validation-matrix.md
  • .coderabbit.yaml
  • .github/workflows/ci.yml
  • .pre-commit-config.yaml
  • .secrets.baseline
  • AGENTS.md
  • CONTRIBUTING.md
  • LICENSE-THIRD-PARTY
  • README.md
  • deploy/Dockerfile
  • docs/source/contributing/code-style.md
  • docs/source/contributing/pr-workflow.md
  • docs/source/contributing/testing.md
  • docs/source/deployment/docker-build.md
  • docs/source/integration/mcp-server.md
  • mcp/Dockerfile
  • mcp/README.md
  • mcp/SECURITY.md
  • mcp/pyproject.toml
  • mcp/scripts/check_license_inventory.py
  • mcp/src/aiq_mcp/jobs.py
  • mcp/tests/test_config_and_packaging.py
  • mcp/tests/test_dependency_compatibility.py
  • mcp/tests/test_deployment_assets.py
  • mcp/tests/test_jobs.py
  • mcp/tests/test_release_checks.py
  • pyproject.toml
  • scripts/dev.sh
  • scripts/setup.sh
📜 Review details
⏰ Context from checks skipped due to timeout. (2)
  • GitHub Check: Run Harbor skill eval
  • GitHub Check: Script Validation
🧰 Additional context used
📓 Path-based instructions (9)
**

⚙️ CodeRabbit configuration file

**:

AI-Q Agent Guidance

Repository-global instructions for coding agents and for humans reviewing
agent-authored changes. These rules apply to every task in this repository.
Task-specific runbooks live in .agents/skills/ — load the
relevant skill before starting a workflow it covers.

Project overview

AI-Q is an NVIDIA AI Blueprint: an enterprise research agent built on the
NeMo Agent Toolkit (NAT). The deployed product is a research blueprint, not
a general skill runtime. New retrieval sources and tools are NAT functions;
agent behavior is driven by workflow YAML, Jinja2 prompts, and a data-source
registry — not by hard-coded logic.

Primary boundaries:

  • Backend Python package: src/aiq_agent/.
  • Data-source and tool packages: sources/ (each is its own package).
  • Frontends and tooling: frontends/ (web UI in frontends/ui/, eval harnesses
    in frontends/benchmarks/).
  • Configs, deployment, docs: configs/, deploy/, docs/.

Stay inside this repository. If your workspace also contains adjacent repos
(for example a sibling NeMo-Relay checkout), do not edit them as part of an AI-Q
change. Treat sources/* as independent packages: prefer the smallest change
scoped to the package you are touching.

Repository structure

Path Purpose
src/aiq_agent/ Backend agent, FastAPI extensions, auth, observability, knowledge
sources/ Data-source / tool packages (e.g. tavily_web_search, google_scholar_paper_search)
configs/ Workflow YAML configs (e.g. config_cli_default.yml)
frontends/ui/ Next.js / React / TypeScript / Tailwind / KUI web UI
frontends/benchmarks/ Eval harnesses: freshqa, deepsearch_qa, deepresearch_bench
deploy/ Docker Compose and Helm/Kubernetes assets; deploy/.env for secrets
docs/source/ ...

Files:

  • LICENSE-THIRD-PARTY
  • docs/source/contributing/code-style.md
  • scripts/dev.sh
  • mcp/README.md
  • deploy/Dockerfile
  • CONTRIBUTING.md
  • scripts/setup.sh
  • docs/source/contributing/pr-workflow.md
  • mcp/pyproject.toml
  • README.md
  • mcp/Dockerfile
  • docs/source/contributing/testing.md
  • AGENTS.md
  • mcp/tests/test_dependency_compatibility.py
  • docs/source/deployment/docker-build.md
  • docs/source/integration/mcp-server.md
  • mcp/tests/test_deployment_assets.py
  • mcp/SECURITY.md
  • mcp/tests/test_config_and_packaging.py
  • mcp/tests/test_release_checks.py
  • mcp/src/aiq_mcp/jobs.py
  • mcp/tests/test_jobs.py
  • mcp/scripts/check_license_inventory.py
  • pyproject.toml
docs/source/contributing/**

⚙️ CodeRabbit configuration file

docs/source/contributing/**:

Code Organization

High-level layout (refer to Architecture Overview for component roles):

src/aiq_agent/
├── agents/              # Chat researcher, shallow/deep research, clarifier
│   ├── chat_researcher/   # Orchestrator, orchestration node (intent + meta + depth), nodes
│   ├── shallow_researcher/
│   ├── deep_researcher/   # See src/aiq_agent/agents/deep_researcher/README.md
│   └── clarifier/
├── common/              # LLM provider, callbacks, prompt utils, data_sources
├── knowledge/           # Schema, factory, base retriever/ingestor, summary store
├── observability/       # OpenTelemetry header redaction exporter
├── auth/                # Auth utilities
└── fastapi_extensions/  # API route extensions

Configs live in configs/; refer to the Customization guide for configuration options. Frontends: frontends/cli, frontends/aiq_api, frontends/debug, frontends/ui. Benchmarks: frontends/benchmarks/. Data sources and Knowledge Layer: sources/.

docs/source/contributing/**:

Code Style

Development Workflow

Helper script:

./scripts/dev.sh help        # List commands
./scripts/dev.sh test        # Run tests
./scripts/dev.sh format      # Format code
./scripts/dev.sh lint        # Lint
./scripts/dev.sh pre-commit  # Format + checks

Otherwise run pre-commit run --all-files, pytest, and formatters directly (refer to Code Quality below).

Code Quality

  • Formatting: ruff (imports/linting) + yapf (PEP 8 base, column_limit=120). The ./scripts/dev.sh format command runs both.
  • Pre-commit: `pre-commit ru...

Files:

  • docs/source/contributing/code-style.md
  • docs/source/contributing/pr-workflow.md
  • docs/source/contributing/testing.md
{docs/**,README.md,CONTRIBUTING.md,SECURITY.md,CODE-OF-CONDUCT.md}

⚙️ CodeRabbit configuration file

{docs/**,README.md,CONTRIBUTING.md,SECURITY.md,CODE-OF-CONDUCT.md}: Review documentation for command accuracy, branch-name consistency, current CI and copy-pr-bot behavior, public
vs internal boundary clarity, stale examples, and links that no longer match the repository layout.

Files:

  • docs/source/contributing/code-style.md
  • CONTRIBUTING.md
  • docs/source/contributing/pr-workflow.md
  • README.md
  • docs/source/contributing/testing.md
  • docs/source/deployment/docker-build.md
  • docs/source/integration/mcp-server.md
mcp/**

📄 CodeRabbit inference engine (CONTRIBUTING.md)

For changes under mcp/, also run uv sync --project mcp --extra dev and uv run --project mcp --extra dev pytest mcp/tests.

Files:

  • mcp/README.md
  • mcp/pyproject.toml
  • mcp/Dockerfile
  • mcp/tests/test_dependency_compatibility.py
  • mcp/tests/test_deployment_assets.py
  • mcp/SECURITY.md
  • mcp/tests/test_config_and_packaging.py
  • mcp/tests/test_release_checks.py
  • mcp/src/aiq_mcp/jobs.py
  • mcp/tests/test_jobs.py
  • mcp/scripts/check_license_inventory.py
deploy/**/*

📄 CodeRabbit inference engine (AGENTS.md)

Never commit secrets or environment-specific hostnames in deployment assets; use deploy/.env for secrets.

Files:

  • deploy/Dockerfile
{deploy/**,configs/**}

⚙️ CodeRabbit configuration file

{deploy/**,configs/**}: Review deployment and config changes for secret separation, safe defaults, local-vs-production behavior, Helm and
Docker portability, and documentation parity. Flag committed credentials, environment-specific NVIDIA internals in
public defaults, and changes that make examples diverge from CI-tested paths.

Files:

  • deploy/Dockerfile
{skills/**,.agents/skills/**,.claude/skills/**,.github/skill-eval/**}

⚙️ CodeRabbit configuration file

{skills/**,.agents/skills/**,.claude/skills/**,.github/skill-eval/**}: Review Agent Skill and skill-eval changes for valid skill metadata, deterministic eval specs, safe handling of
credentials, and clear generated-output boundaries. Do not flag SKILL.md files for missing SPDX headers when the
entrypoint intentionally starts with YAML frontmatter.

Files:

  • .agents/skills/aiq-maintain-ci/SKILL.md
  • .agents/skills/aiq-release-qa/references/validation-matrix.md
  • .agents/skills/aiq-release-qa/SKILL.md
  • .agents/skills/aiq-maintain-ci/references/workflows-and-hooks.md
{pyproject.toml,uv.lock,mcp/pyproject.toml,mcp/uv.lock}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Dependency changes must leave both project locks current: check the root with uv lock --check and MCP with uv lock --project mcp --check.

Files:

  • mcp/pyproject.toml
  • pyproject.toml
{.github/**,ci/**,.pre-commit-config.yaml,pyproject.toml,uv.lock,mcp/pyproject.toml,mcp/uv.lock}

⚙️ CodeRabbit configuration file

{.github/**,ci/**,.pre-commit-config.yaml,pyproject.toml,uv.lock,mcp/pyproject.toml,mcp/uv.lock}: Review automation and packaging changes for least-privilege permissions, pinned versions where appropriate,
copy-pr-bot pull-request/ branch behavior, reproducible uv/npm setup, secret handling, and consistency with
the documented validation matrix.

Files:

  • mcp/pyproject.toml
  • .pre-commit-config.yaml
  • .github/workflows/ci.yml
  • pyproject.toml
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T18:58:51.275Z
Learning: These rules apply to every task in this repository; load the relevant task-specific skill from `.agents/skills/` before starting a workflow it covers.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T18:58:51.275Z
Learning: Stay inside this repository; do not edit adjacent repositories as part of an AI-Q change, and prefer the smallest change scoped to the package you are touching.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T18:58:51.275Z
Learning: Do not commit secrets, tokens, or environment-specific hostnames; use environment variables and `SecretStr`, and resolve API keys at runtime.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T18:58:51.275Z
Learning: Never print or log secret values, including in tool output or error messages.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T18:58:51.275Z
Learning: Missing-secret paths must degrade gracefully (stub or skip) rather than crash or leak.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T18:58:51.275Z
Learning: Respect authenticated data sources: honor `requires_auth`, per-user token pass-through, and backend token validators, and apply owner guardrails before loading protected report or artifact context into an agent.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T18:58:51.275Z
Learning: Do not weaken or bypass `AuthMiddleware`, validators, or auth gating without a prior design discussion.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T18:58:51.275Z
Learning: For substantial behavior, auth, UI, or architecture changes, open a design discussion before coding rather than landing a large unreviewed change.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T18:58:51.275Z
Learning: Every commit must be signed off with `git commit -s` and include a `Signed-off-by` trailer.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T18:58:51.275Z
Learning: Keep pull requests scoped: avoid unrelated files, accidental generated artifacts, and secrets, and provide validation evidence for the changes made.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T18:59:03.770Z
Learning: Search existing issues and pull requests before opening new work.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T18:59:03.770Z
Learning: Open an issue or discussion before large design changes, public API changes, deployment changes, or contributor workflow changes.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T18:59:03.770Z
Learning: Do not include secrets, credentials, private hostnames, internal-only logs, customer data, or generated local artifacts in contributions.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T18:59:03.770Z
Learning: Target the `develop` branch unless a maintainer asks you to use a release branch.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T18:59:03.770Z
Learning: Make the smallest coherent change and add or update tests for behavior changes.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T18:59:03.770Z
Learning: Sign off every commit with `git commit -s`; commits without sign-off may be rejected.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T18:59:03.770Z
Learning: Run the relevant local validation before opening the pull request and include the exact output or workflow link in the PR.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T18:59:03.770Z
Learning: Open a pull request into `develop` and fill out the PR template with exact validation evidence.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T18:59:03.770Z
Learning: Address review feedback until required checks and code-owner review pass.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T18:59:03.770Z
Learning: For deployment changes, run the relevant Helm or compose validation and describe the environment used.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T18:59:03.770Z
Learning: AI-Q uses push-triggered GitHub Actions; pull requests are mirrored by copy-pr-bot after `/ok to test`, and maintainers can request bot-driven merge with `/merge` when repository rules are satisfied.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T18:59:03.770Z
Learning: All contributors must sign off their commits to certify DCO compliance and acknowledgment that contributions are public and may be redistributed.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T18:59:08.070Z
Learning: Use `./scripts/dev.sh help`, `./scripts/dev.sh test`, `./scripts/dev.sh format`, `./scripts/dev.sh lint`, and `./scripts/dev.sh pre-commit` for the documented development workflow; otherwise run `pre-commit run --all-files`, `pytest`, and the relevant formatters directly.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T18:59:12.430Z
Learning: Create a focused branch from `develop`, make changes, and add or update tests before opening a pull request.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T18:59:12.430Z
Learning: Run the narrowest relevant local checks for your change and record the exact commands in the pull request description.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T18:59:12.430Z
Learning: Open pull requests into `develop` unless a maintainer asks you to target a release branch.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T18:59:12.430Z
Learning: Address review feedback until required checks, code-owner review, and review-thread resolution pass.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T18:59:12.430Z
Learning: Use the repository's configured merge/bot workflow when available; otherwise follow the normal protected-branch merge flow.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T18:59:12.430Z
Learning: Sign off all commits with a Developer's Certificate of Origin (DCO) using `git commit -s` so each commit includes a `Signed-off-by` line.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T18:59:12.430Z
Learning: By contributing, certify compliance with the project's Developer's Certificate of Origin 1.1 statement, including that the contribution is properly licensed and that your sign-off may be retained indefinitely.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T18:59:12.430Z
Learning: For MCP changes, validate the MCP subproject independently with its own dev environment and test command.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T18:59:12.430Z
Learning: For UI changes, run the UI project's lint, type-check, test, and build commands from `frontends/ui`.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-09T18:59:12.430Z
Learning: Repository owners, organization members, and collaborators may request additional validation, including NVSkills validation with `/nvskills-ci`.
🪛 SkillSpector (2.3.7)
.agents/skills/aiq-release-qa/SKILL.md

[error] 112: [PE3] Credential Access: Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Remediation: Remove references to credential paths. Use environment variables or secrets managers. For docs, use placeholder paths (e.g., /path/to/config). Never load .env or token files in production code paths.

(Privilege Escalation (PE3))


[error] 112: [PE3] Credential Access: Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Remediation: Remove references to credential paths. Use environment variables or secrets managers. For docs, use placeholder paths (e.g., /path/to/config). Never load .env or token files in production code paths.

(Privilege Escalation (PE3))


[error] 112: [PE3] Credential Access: Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Remediation: Remove references to credential paths. Use environment variables or secrets managers. For docs, use placeholder paths (e.g., /path/to/config). Never load .env or token files in production code paths.

(Privilege Escalation (PE3))

🔇 Additional comments (39)
LICENSE-THIRD-PARTY (1)

8-11: LGTM!

.secrets.baseline (1)

136-136: LGTM!

Also applies to: 354-358

docs/source/contributing/code-style.md (1)

24-25: 📐 Maintainability & Code Quality

Verify the pre-commit matrix still matches the hook set.

pre-commit run --all-files only covers lock checks if explicit hooks are present; otherwise this doc now overstates the validation contributors get from the command.

Source: Path instructions

scripts/dev.sh (1)

8-11: LGTM!

Also applies to: 61-61

mcp/README.md (2)

109-115: 📐 Maintainability & Code Quality

Verify the standalone wheel build command.

uv build mcp --wheel is a tool-specific invocation; please confirm it is valid for the pinned uv release, otherwise this doc will point contributors at a failing command.


3-108: LGTM!

Also applies to: 117-154

.coderabbit.yaml (1)

99-103: LGTM!

deploy/Dockerfile (1)

81-90: 🩺 Stability & Availability

Verify uv pip install accepts --no-sources here.

If the pinned uv release rejects that flag for uv pip install, the builder stage will fail at image build time.

Source: Path instructions

docs/source/deployment/docker-build.md (1)

45-47: LGTM!

Also applies to: 58-73

.agents/skills/aiq-maintain-ci/SKILL.md (1)

39-52: LGTM!

CONTRIBUTING.md (1)

32-42: LGTM!

.agents/skills/aiq-release-qa/references/validation-matrix.md (1)

16-19: LGTM!

Also applies to: 50-62

scripts/setup.sh (1)

46-55: LGTM!

Also applies to: 126-127

docs/source/contributing/pr-workflow.md (1)

30-36: LGTM!

mcp/pyproject.toml (1)

55-81: LGTM!

Verified the scoped-override table syntax ({ package = { name, version }, dependencies = [...] }) against uv's documented resolution behavior — this is valid and matches the documented pattern for constraining a specific package's transitive dependency.

README.md (1)

305-326: LGTM!

The cryptography<47 (root) vs cryptography==48.0.1 (MCP frozen profile) distinction is consistent with the override comment in mcp/pyproject.toml.

mcp/Dockerfile (1)

1-52: LGTM!

The multi-stage layout (build wheels into /opt/venv via --no-editable --frozen, then copy only the venv/config/license into a minimal non-root release stage) is a sound pattern, and the port/health-check/entrypoint wiring lines up with the aiq-mcp compose service referencing this Dockerfile.

Also applies to: 56-93

.github/workflows/ci.yml (3)

72-72: Unpinned postgres:16-alpine service image and actions/upload-artifact@v4 references (new instances of a previously-flagged pattern).

This PR adds a third actions/upload-artifact@v4 use (mcp-release-evidence, mcp-compose-logs) and keeps postgres:16-alpine unpinned, consistent with the earlier review comment on this file about pinning images/actions to immutable digests.

Also applies to: 154-154, 284-284, 313-313


242-266: 🔒 Security & Privacy | ⚡ Quick win

Verify uv audit/uv export preview-feature flag names and the scope of the ignored advisory.

Two things worth double-checking here:

  1. uv audit is a preview feature, and running it as-is will produce an experimental warning. Add --preview-features audit only if you want to suppress the warning. The workflow instead passes --preview-features audit-command,json-output, which doesn't match the documented audit feature name. Unrecognized preview feature names only warn, they don't fail the build, but the intended warning-suppression likely isn't happening.
  2. --ignore-until-fixed GHSA-f4j7-r4q5-qw2c permanently (until a fix appears) exempts this advisory from the production-lock gate; the public advisory record for this ID has no known source code · Dependabot alerts are not supported on this advisory because it does not have a package from a supported ecosystem with an affected and fixed version, so it's worth confirming this ID actually maps to a real MCP dependency vulnerability and not a stale/incorrect reference.

37-53: LGTM! Postgres service wiring, isolated MCP venv provisioning, mandatory 90%-coverage MCP test lane with skipped-test guard, SBOM/license evidence, and Compose smoke test/teardown are otherwise well-structured.

Also applies to: 67-165, 184-322

docs/source/contributing/testing.md (1)

10-17: LGTM!

.pre-commit-config.yaml (2)

84-89: 📐 Maintainability & Code Quality | ⚡ Quick win

Verify pytest-mcp push-stage hook is runnable locally without CI's dedicated Postgres.

This hook runs pytest mcp/tests with --cov-fail-under=90, but the CI test job only provisions Postgres via a service container and AIQ_MCP_TEST_DB_URL. If mcp/tests requires a live Postgres and a contributor runs pre-commit run --all-files --hook-stage push locally without one configured, the hook will fail with no guidance in the docs.


61-66: 🚀 Performance & Scalability

Confirm uv-lock-mcp covers every MCP path dependency. The current files regex only watches sources/knowledge_layer and sources/tavily_web_search; if mcp/pyproject.toml depends on any other sources/* package, edits there will not retrigger uv lock --project mcp --check.

.agents/skills/aiq-release-qa/SKILL.md (1)

38-41: LGTM!

Also applies to: 72-87, 104-108

.agents/skills/aiq-maintain-ci/references/workflows-and-hooks.md (1)

16-19: LGTM!

Also applies to: 40-50

AGENTS.md (2)

43-43: LGTM!

Also applies to: 55-61


105-109: 📐 Maintainability & Code Quality

AGENTS.md:105-109 — align the cryptography note with pyproject.toml
This says the root workspace stays on cryptography>=46.0.6,<47 while only mcp/ uses 48.0.1, but the dependency change in this PR appears to target the root project. One of these is stale.

mcp/src/aiq_mcp/jobs.py (1)

373-404: LGTM! Heartbeat resilience fix looks correct: transient store failures no longer kill the heartbeat loop, and _FAILURE_HANDLER/context cleanup is now guaranteed via the nested finally even if heartbeat teardown raises. This resolves the previously flagged critical issue.

pyproject.toml (2)

100-100: LGTM!

Also applies to: 157-157, 184-185, 242-242


211-226: 📐 Maintainability & Code Quality

Clarify the cryptography constraint and mcp-tests group. If the change is meant to affect the root mcp-tests group rather than [project].dependencies, add a short note explaining why this root test-only pin is needed while mcp/ remains excluded from the workspace.

mcp/tests/test_dependency_compatibility.py (1)

26-31: LGTM!

docs/source/integration/mcp-server.md (1)

32-52: LGTM!

Dependency-isolation and container-deployment guidance is internally consistent with mcp/SECURITY.md and the packaging contract tests (cryptography floor/override split, mcp/uv.lock usage, loopback-only Compose stack).

Also applies to: 221-249

mcp/tests/test_deployment_assets.py (1)

38-50: LGTM!

Strict allowlisted COPY line contract plus the new root-Dockerfile --no-sources --no-deps -e . assertion give solid drift detection for the multi-stage build.

Also applies to: 62-96

mcp/SECURITY.md (1)

27-52: LGTM!

The uv export/uv audit preview-feature flags (sbom-export, audit-command, json-output) match documented uv usage, and the cryptography override rationale is consistent with the packaging tests.

Also applies to: 80-101

mcp/tests/test_config_and_packaging.py (1)

129-216: LGTM!

Root/MCP lock and source-of-truth split (workspace exclusion, scoped cryptography override, editable path mapping) is thoroughly and correctly asserted.

mcp/tests/test_release_checks.py (1)

176-220: LGTM!

mcp/tests/test_jobs.py (1)

676-760: LGTM!

Good coverage: transient heartbeat failures retry without leaking the simulated credential or raw job id, and unexpected heartbeat-task crashes still force cleanup with sanitized logs. Directly exercises the no-secret-leakage requirement.

mcp/scripts/check_license_inventory.py (2)

214-236: LGTM!

validate_lock_sources() correctly rejects any non-registry, non-editable source and enforces the exact local-path/registry contract; wiring it before build_inventory() in main() is the right order.

Also applies to: 433-448


189-211: 🗄️ Data Integrity & Integration

Check uv:workspace:path handling for local MCP packages. validate_sbom rejects any purl-less component with uv:workspace:path; if uv export --preview-features sbom-export starts tagging the approved path/editable deps from mcp/pyproject.toml, CI will fail them even though they are allowed.

@AjayThorve AjayThorve requested a review from a team July 10, 2026 21:04
AjayThorve added a commit that referenced this pull request Jul 10, 2026
#### Overview

Refresh the AI-Q documentation against the live 2.2 milestone and
current `develop` implementation while keeping branch-facing
documentation portable across future release cuts.

- keeps the root README version-free: “What’s New” highlights current
capabilities without embedding release numbers, RC status, or a
branch-cut lifecycle
- keeps version-specific 2.2 targeting in the existing changelog, which
is the detailed unreleased ledger; no separate release-notes document is
introduced
- makes the roadmap describe implementation in the checked-out branch
rather than implying availability in a published release
- updates configuration, deployment, quick-start, profiling, and
docs-navigation wording to describe current behavior instead of a “2.2
candidate”
- documents the newly merged artifact lifecycle (#314), Helm
release-namespace behavior (#309), and async trace hierarchy (#321)
- keeps the remaining open capabilities explicit: no per-job
isolated/attested OpenShell lifecycle (#298) and no standalone public
AI-Q MCP server (#319)
- resolves Linette's review feedback across link-referral wording,
terminology, and documentation clarity
- preserves runtime boundaries for advisory routing, focused
configuration profiles, MCP reconnect behavior, narrow forward-only
encryption, best-effort artifact capture, and best-effort tokenomics
phase attribution

Milestone audit as of July 10, 2026: 49 items (47 PRs and 2 issues),
including 41 PRs merged to `develop`, one PR merged only to
`release/2.1`, three open PRs (#298, #319, and this documentation PR),
and two closed-unmerged PRs superseded by merged work. AI-Q `v2.1.0`
remains the latest stable release. `v2.2.0-rc1` is a prerelease snapshot
from `develop`; there is no final `v2.2.0` tag yet, and `release/2.2`
has not been cut. These lifecycle details intentionally remain outside
the develop-facing README.

#### Validation

- `make -C docs SPHINXBUILD=../.venv/bin/sphinx-build SPHINXOPTS='-W
--keep-going -n' html`
- `make -C docs SPHINXBUILD=../.venv/bin/sphinx-build linkcheck`
- `pre-commit run --all-files`
- `git diff --check origin/develop...HEAD`
- independent release-lifecycle, version-free wording, milestone,
review-thread, and semantic whole-diff reviews found no remaining
Critical or Important issues

- [x] I ran the relevant local checks or explained why they are not
applicable.
- [x] I added or updated tests for behavior changes. Not applicable:
this PR changes documentation only.
- [x] I updated documentation for user-facing or contributor-facing
changes.
- [x] I confirmed this PR does not include secrets, credentials, or
internal-only data.
- [x] I certify this contribution under the Developer Certificate of
Origin (DCO) and signed my commits with `git commit -s` or an equivalent
sign-off.

#### Where should reviewers start?

1. `README.md` for the version-free “What’s New” highlights and
current-branch roadmap semantics.
2. `CHANGELOG.md` for the detailed unreleased 2.2 ledger and release
lifecycle.
3. `docs/source/architecture/agents/deep-researcher.md` for the routed
planner/researcher/writer contract.
4. `docs/source/architecture/data-flow.md` and
`docs/source/integration/rest-api.md` for artifact checkpoint, SSE,
replay, and authorization semantics.
5. `docs/source/deployment/kubernetes.md` and
`docs/source/deployment/observability.md` for the newly merged namespace
and trace-hierarchy behavior.

#### Related Issues

- Relates to the [AI-Q v2.2
milestone](https://github.com/NVIDIA-AI-Blueprints/aiq/milestone/1).
- Documents merged changes from #309, #314, and #321.
- Keeps open #298 and #319 explicitly out of the candidate scope.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Documentation**
* Updated “Unreleased” release notes targeting AI-Q v2.2.0, including
deep research workflow changes, async job reporting, and
sandbox/artifact behavior.
* Added/expanded REST API documentation for event-derived job state and
durable artifact listing/streaming.
* Documented OpenSearch support for knowledge retrieval and multiple
paper-search providers, plus refined configuration, guardrails, MCP
OAuth behavior, and observability trace hierarchy.
* **Chores**
  * Refreshed secrets baseline metadata timestamps/line references only.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Ajay Thorve <athorve@nvidia.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
mcp/src/aiq_mcp/job_store.py (1)

250-274: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

record_poll's fallback path doesn't re-check principal.

When the UPDATE ... RETURNING misses (terminal state or principal mismatch), the fallback return await self.get(job_id) returns the row for any principal, unlike wait_for_completion in jobs.py, which explicitly checks job.principal != principal. Not exploitable today since every caller shares the constant anonymous principal, but it's an inconsistent, latent authorization gap if multi-principal support is ever added.

🛡️ Proposed fix
         if row is not None:
             return _row_to_job(row)
-        return await self.get(job_id)
+        job = await self.get(job_id)
+        if job is not None and job.principal != principal:
+            return None
+        return job
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mcp/src/aiq_mcp/job_store.py` around lines 250 - 274, Update record_poll so
its fallback lookup enforces the supplied principal before returning a job.
After get(job_id), return the job only when it is absent or its principal
matches principal; otherwise return None, while preserving the existing
successful UPDATE path.
mcp/tests/test_postgres_job_store.py (1)

640-670: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate Postgres test-infrastructure helpers across two test files.

_ensure_database, _maintenance_url, _quote_database_name, the safe-identifier regex, and the postgres_url fixture skip/reset lifecycle are reimplemented nearly identically in both files (this diff even makes the same one-line message tweak in both). A future correctness or security fix to identifier quoting would need to be applied twice.

  • mcp/tests/test_postgres_job_store.py#L640-L670: extract _ensure_database, _maintenance_url, _quote_database_name, and the identifier regex into a shared mcp/tests/conftest.py (or a _pg_test_utils module) and import it here.
  • mcp/tests/test_checkpoint_todos.py#L420-L477: replace the duplicated _ensure_database/_maintenance_url/_quote_database_name/regex with the same shared utility.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mcp/tests/test_postgres_job_store.py` around lines 640 - 670, Extract the
shared Postgres test helpers _ensure_database, _maintenance_url,
_quote_database_name, and the safe-identifier regex into one utility module,
then import and reuse them in mcp/tests/test_postgres_job_store.py lines 640-670
and mcp/tests/test_checkpoint_todos.py lines 420-477. Remove the duplicated
definitions while preserving each file’s existing postgres_url fixture
skip/reset lifecycle and shared error-message behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/ci.yml:
- Around line 112-118: Update the “Validate isolated dependency environments”
workflow step to pass --verify-imports when invoking
mcp/scripts/check_runtime_dependencies.py with the production test-venv Python,
ensuring the import canary runs against the --no-dev --no-editable dependency
closure while preserving the existing dependency check.

In `@docs/source/contributing/pr-workflow.md`:
- Around line 30-36: Update the MCP validation section in pr-workflow.md to
include both lock checks: the root-project lock and the MCP project lock,
alongside the existing sync and pytest commands. Preserve the current MCP test
commands and ensure contributors are instructed to verify both lockfiles are
current.

In `@mcp/scripts/check_license_inventory.py`:
- Around line 214-236: Add tests for validate_lock_sources() covering the
approved local-source set and rejection of at least one unapproved registry or
malformed editable source. Use temporary lock files or equivalent fixtures so
the tests exercise parsing and validation through validate_lock_sources(),
including the expected success and ValueError paths.

In `@mcp/src/aiq_mcp/server.py`:
- Line 143: Implement per-caller rate limiting for the unauthenticated research
submission endpoint, covering the request paths around the handlers at lines
183-188, 215, and 413-423, rather than only enforcing max_query_chars. Prefer
the existing deployment’s reverse-proxy/ingress mechanism or add Starlette
middleware, and ensure excess requests are rejected before starting LLM/tool
research jobs.

---

Outside diff comments:
In `@mcp/src/aiq_mcp/job_store.py`:
- Around line 250-274: Update record_poll so its fallback lookup enforces the
supplied principal before returning a job. After get(job_id), return the job
only when it is absent or its principal matches principal; otherwise return
None, while preserving the existing successful UPDATE path.

In `@mcp/tests/test_postgres_job_store.py`:
- Around line 640-670: Extract the shared Postgres test helpers
_ensure_database, _maintenance_url, _quote_database_name, and the
safe-identifier regex into one utility module, then import and reuse them in
mcp/tests/test_postgres_job_store.py lines 640-670 and
mcp/tests/test_checkpoint_todos.py lines 420-477. Remove the duplicated
definitions while preserving each file’s existing postgres_url fixture
skip/reset lifecycle and shared error-message behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 1e4a7271-3b16-4d49-83fb-a9eca46bebc4

📥 Commits

Reviewing files that changed from the base of the PR and between afc41be and 05882bf.

⛔ Files ignored due to path filters (2)
  • mcp/uv.lock is excluded by !**/*.lock
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (46)
  • .agents/skills/aiq-maintain-ci/SKILL.md
  • .agents/skills/aiq-maintain-ci/references/workflows-and-hooks.md
  • .agents/skills/aiq-release-qa/SKILL.md
  • .agents/skills/aiq-release-qa/references/validation-matrix.md
  • .coderabbit.yaml
  • .github/workflows/ci.yml
  • .pre-commit-config.yaml
  • .secrets.baseline
  • AGENTS.md
  • CONTRIBUTING.md
  • LICENSE-THIRD-PARTY
  • README.md
  • deploy/Dockerfile
  • docs/source/contributing/code-style.md
  • docs/source/contributing/pr-workflow.md
  • docs/source/contributing/testing.md
  • docs/source/deployment/docker-build.md
  • docs/source/get-started/installation.md
  • docs/source/integration/mcp-server.md
  • frontends/aiq_api/src/aiq_api/jobs/runner.py
  • mcp/Dockerfile
  • mcp/README.md
  • mcp/REFERENCE_PARITY.md
  • mcp/SECURITY.md
  • mcp/pyproject.toml
  • mcp/scripts/check_license_inventory.py
  • mcp/scripts/check_runtime_dependencies.py
  • mcp/src/aiq_mcp/job_store.py
  • mcp/src/aiq_mcp/jobs.py
  • mcp/src/aiq_mcp/server.py
  • mcp/tests/test_checkpoint_todos.py
  • mcp/tests/test_client_session_integration.py
  • mcp/tests/test_config_and_packaging.py
  • mcp/tests/test_dependency_compatibility.py
  • mcp/tests/test_deployment_assets.py
  • mcp/tests/test_imports.py
  • mcp/tests/test_jobs.py
  • mcp/tests/test_postgres_job_store.py
  • mcp/tests/test_release_checks.py
  • mcp/tests/test_runtime_dependencies.py
  • mcp/tests/test_server_runtime.py
  • pyproject.toml
  • scripts/dev.sh
  • scripts/setup.sh
  • skills/aiq-research/skill-card.md
  • tests/aiq_agent/jobs/test_runner.py
📜 Review details
🧰 Additional context used
📓 Path-based instructions (14)
**/*.{py,ts,tsx,js,jsx,yml,yaml,json,md}

📄 CodeRabbit inference engine (AGENTS.md)

Never commit secrets, tokens, or environment-specific hostnames; use environment variables and SecretStr, and resolve API keys at runtime.

Files:

  • docs/source/contributing/pr-workflow.md
  • docs/source/get-started/installation.md
  • CONTRIBUTING.md
  • mcp/REFERENCE_PARITY.md
  • mcp/README.md
  • frontends/aiq_api/src/aiq_api/jobs/runner.py
  • docs/source/contributing/code-style.md
  • skills/aiq-research/skill-card.md
  • README.md
  • AGENTS.md
  • tests/aiq_agent/jobs/test_runner.py
  • mcp/tests/test_runtime_dependencies.py
  • mcp/tests/test_deployment_assets.py
  • mcp/tests/test_dependency_compatibility.py
  • mcp/scripts/check_runtime_dependencies.py
  • docs/source/contributing/testing.md
  • mcp/SECURITY.md
  • docs/source/integration/mcp-server.md
  • docs/source/deployment/docker-build.md
  • mcp/tests/test_client_session_integration.py
  • mcp/tests/test_release_checks.py
  • mcp/src/aiq_mcp/job_store.py
  • mcp/tests/test_imports.py
  • mcp/tests/test_checkpoint_todos.py
  • mcp/src/aiq_mcp/server.py
  • mcp/scripts/check_license_inventory.py
  • mcp/tests/test_config_and_packaging.py
  • mcp/tests/test_server_runtime.py
  • mcp/src/aiq_mcp/jobs.py
  • mcp/tests/test_postgres_job_store.py
  • mcp/tests/test_jobs.py
docs/source/**/*

📄 CodeRabbit inference engine (AGENTS.md)

Update documentation when behavior, configuration, or workflows change; keep documentation canonical rather than duplicating full documentation pages into skills.

Files:

  • docs/source/contributing/pr-workflow.md
  • docs/source/get-started/installation.md
  • docs/source/contributing/code-style.md
  • docs/source/contributing/testing.md
  • docs/source/integration/mcp-server.md
  • docs/source/deployment/docker-build.md
**/*

📄 CodeRabbit inference engine (AGENTS.md)

**/*: Stay within this repository, do not edit adjacent repositories, and keep changes to sources/* scoped to the smallest relevant independent package.
Run the narrowest relevant validation command first and broaden to the full suite only when a change crosses shared boundaries.
Keep the root uv.lock and mcp/uv.lock as separate dependency resolutions; scope the cryptography==48.0.1 override to mcp/, while the root uses cryptography>=46.0.6,<47.
Keep pull requests scoped, avoid unrelated files and generated artifacts, do not include secrets, and provide validation evidence.
Every commit must include DCO sign-off using git commit -s, with a Signed-off-by trailer.
For substantial behavior, authentication, UI, or architecture changes, open a design discussion before coding.

**/*: Do not include secrets, credentials, private hostnames, internal-only logs, customer data, or generated local artifacts in contributions.
Add or update tests for behavior changes.
Run the narrowest local validation command that covers the change and include exact output or a workflow link in the pull request.
For deployment changes, run the relevant Helm or Compose validation and describe the environment used.
Target the develop branch unless a maintainer explicitly requests a release branch.
Sign off every commit with git commit -s; commits without sign-off may be rejected.
Open an issue or discussion before large design changes, public APIs, deployment changes, or contributor workflow changes.
Make the smallest coherent change and address review feedback until required checks and code-owner review pass.

Files:

  • docs/source/contributing/pr-workflow.md
  • LICENSE-THIRD-PARTY
  • docs/source/get-started/installation.md
  • CONTRIBUTING.md
  • scripts/setup.sh
  • mcp/REFERENCE_PARITY.md
  • mcp/README.md
  • frontends/aiq_api/src/aiq_api/jobs/runner.py
  • docs/source/contributing/code-style.md
  • skills/aiq-research/skill-card.md
  • README.md
  • deploy/Dockerfile
  • mcp/Dockerfile
  • AGENTS.md
  • tests/aiq_agent/jobs/test_runner.py
  • mcp/tests/test_runtime_dependencies.py
  • mcp/tests/test_deployment_assets.py
  • scripts/dev.sh
  • mcp/tests/test_dependency_compatibility.py
  • mcp/scripts/check_runtime_dependencies.py
  • docs/source/contributing/testing.md
  • mcp/SECURITY.md
  • docs/source/integration/mcp-server.md
  • mcp/pyproject.toml
  • docs/source/deployment/docker-build.md
  • mcp/tests/test_client_session_integration.py
  • mcp/tests/test_release_checks.py
  • mcp/src/aiq_mcp/job_store.py
  • mcp/tests/test_imports.py
  • mcp/tests/test_checkpoint_todos.py
  • mcp/src/aiq_mcp/server.py
  • mcp/scripts/check_license_inventory.py
  • pyproject.toml
  • mcp/tests/test_config_and_packaging.py
  • mcp/tests/test_server_runtime.py
  • mcp/src/aiq_mcp/jobs.py
  • mcp/tests/test_postgres_job_store.py
  • mcp/tests/test_jobs.py
docs/source/contributing/**/*.{py,md,ipynb}

📄 CodeRabbit inference engine (docs/source/contributing/code-style.md)

Run pre-commit checks across all files; these include Ruff checks and formatting, lock-file checks, secret detection, notebook output clearing, and Markdown link validation.

Files:

  • docs/source/contributing/pr-workflow.md
  • docs/source/contributing/code-style.md
  • docs/source/contributing/testing.md
docs/source/contributing/**/*

📄 CodeRabbit inference engine (docs/source/contributing/pr-workflow.md)

For each change, run the narrowest relevant local validation checks and record the exact commands in the pull request description, including repository checks (uv run ruff check ., uv run ruff format --check ., and uv run pytest), MCP checks when applicable, and UI checks when applicable.

Files:

  • docs/source/contributing/pr-workflow.md
  • docs/source/contributing/code-style.md
  • docs/source/contributing/testing.md
{docs/**,README.md,CONTRIBUTING.md,SECURITY.md,CODE-OF-CONDUCT.md}

⚙️ CodeRabbit configuration file

{docs/**,README.md,CONTRIBUTING.md,SECURITY.md,CODE-OF-CONDUCT.md}: Review documentation for command accuracy, branch-name consistency, current CI and copy-pr-bot behavior, public
vs internal boundary clarity, stale examples, and links that no longer match the repository layout.

Files:

  • docs/source/contributing/pr-workflow.md
  • docs/source/get-started/installation.md
  • CONTRIBUTING.md
  • docs/source/contributing/code-style.md
  • README.md
  • docs/source/contributing/testing.md
  • docs/source/integration/mcp-server.md
  • docs/source/deployment/docker-build.md
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Use Ruff for Python linting and formatting with line length 120, target Python 3.11, rule sets E, F, W, I, PL, and UP; use single-line imports as configured.
Never print or log secret values, including in tool output or error messages.

Files:

  • frontends/aiq_api/src/aiq_api/jobs/runner.py
  • tests/aiq_agent/jobs/test_runner.py
  • mcp/tests/test_runtime_dependencies.py
  • mcp/tests/test_deployment_assets.py
  • mcp/tests/test_dependency_compatibility.py
  • mcp/scripts/check_runtime_dependencies.py
  • mcp/tests/test_client_session_integration.py
  • mcp/tests/test_release_checks.py
  • mcp/src/aiq_mcp/job_store.py
  • mcp/tests/test_imports.py
  • mcp/tests/test_checkpoint_todos.py
  • mcp/src/aiq_mcp/server.py
  • mcp/scripts/check_license_inventory.py
  • mcp/tests/test_config_and_packaging.py
  • mcp/tests/test_server_runtime.py
  • mcp/src/aiq_mcp/jobs.py
  • mcp/tests/test_postgres_job_store.py
  • mcp/tests/test_jobs.py
**/*.{py,pyi}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.{py,pyi}: Run uv run ruff check . and uv run ruff format --check . for Python changes.
Run uv run pytest for relevant Python changes.

Files:

  • frontends/aiq_api/src/aiq_api/jobs/runner.py
  • tests/aiq_agent/jobs/test_runner.py
  • mcp/tests/test_runtime_dependencies.py
  • mcp/tests/test_deployment_assets.py
  • mcp/tests/test_dependency_compatibility.py
  • mcp/scripts/check_runtime_dependencies.py
  • mcp/tests/test_client_session_integration.py
  • mcp/tests/test_release_checks.py
  • mcp/src/aiq_mcp/job_store.py
  • mcp/tests/test_imports.py
  • mcp/tests/test_checkpoint_todos.py
  • mcp/src/aiq_mcp/server.py
  • mcp/scripts/check_license_inventory.py
  • mcp/tests/test_config_and_packaging.py
  • mcp/tests/test_server_runtime.py
  • mcp/src/aiq_mcp/jobs.py
  • mcp/tests/test_postgres_job_store.py
  • mcp/tests/test_jobs.py
{src/aiq_agent/fastapi_extensions/**,frontends/aiq_api/src/aiq_api/**}

⚙️ CodeRabbit configuration file

{src/aiq_agent/fastapi_extensions/**,frontends/aiq_api/src/aiq_api/**}: Treat API, auth, and job-runner changes as externally visible contracts. Check authorization boundaries,
request tracing, async job lifecycle, websocket reconnect behavior, error responses, and cross-user data isolation.
Require tests for route behavior, access decisions, and job state transitions when those surfaces change.

Files:

  • frontends/aiq_api/src/aiq_api/jobs/runner.py
{skills/**,.agents/skills/**,.claude/skills/**,.github/skill-eval/**}

⚙️ CodeRabbit configuration file

{skills/**,.agents/skills/**,.claude/skills/**,.github/skill-eval/**}: Review Agent Skill and skill-eval changes for valid skill metadata, deterministic eval specs, safe handling of
credentials, and clear generated-output boundaries. Do not flag SKILL.md files for missing SPDX headers when the
entrypoint intentionally starts with YAML frontmatter.

Files:

  • skills/aiq-research/skill-card.md
  • .agents/skills/aiq-maintain-ci/SKILL.md
  • .agents/skills/aiq-maintain-ci/references/workflows-and-hooks.md
  • .agents/skills/aiq-release-qa/references/validation-matrix.md
  • .agents/skills/aiq-release-qa/SKILL.md
{deploy/**,configs/**}

⚙️ CodeRabbit configuration file

{deploy/**,configs/**}: Review deployment and config changes for secret separation, safe defaults, local-vs-production behavior, Helm and
Docker portability, and documentation parity. Flag committed credentials, environment-specific NVIDIA internals in
public defaults, and changes that make examples diverge from CI-tested paths.

Files:

  • deploy/Dockerfile
.agents/skills/**/*

📄 CodeRabbit inference engine (AGENTS.md)

Use maintainer skills from .agents/skills/ for task-specific repository workflows; do not treat API-consumer skills in skills/ as an in-product runtime.

Files:

  • .agents/skills/aiq-maintain-ci/SKILL.md
  • .agents/skills/aiq-maintain-ci/references/workflows-and-hooks.md
  • .agents/skills/aiq-release-qa/references/validation-matrix.md
  • .agents/skills/aiq-release-qa/SKILL.md
mcp/**/*.py

📄 CodeRabbit inference engine (CONTRIBUTING.md)

For changes under mcp/, run the MCP project's development dependency sync and uv run --project mcp --extra dev pytest mcp/tests.

Files:

  • mcp/tests/test_runtime_dependencies.py
  • mcp/tests/test_deployment_assets.py
  • mcp/tests/test_dependency_compatibility.py
  • mcp/scripts/check_runtime_dependencies.py
  • mcp/tests/test_client_session_integration.py
  • mcp/tests/test_release_checks.py
  • mcp/src/aiq_mcp/job_store.py
  • mcp/tests/test_imports.py
  • mcp/tests/test_checkpoint_todos.py
  • mcp/src/aiq_mcp/server.py
  • mcp/scripts/check_license_inventory.py
  • mcp/tests/test_config_and_packaging.py
  • mcp/tests/test_server_runtime.py
  • mcp/src/aiq_mcp/jobs.py
  • mcp/tests/test_postgres_job_store.py
  • mcp/tests/test_jobs.py
{.github/**,ci/**,.pre-commit-config.yaml,pyproject.toml,uv.lock,mcp/pyproject.toml,mcp/uv.lock}

⚙️ CodeRabbit configuration file

{.github/**,ci/**,.pre-commit-config.yaml,pyproject.toml,uv.lock,mcp/pyproject.toml,mcp/uv.lock}: Review automation and packaging changes for least-privilege permissions, pinned versions where appropriate,
copy-pr-bot pull-request/ branch behavior, reproducible uv/npm setup, secret handling, and consistency with
the documented validation matrix.

Files:

  • .pre-commit-config.yaml
  • mcp/pyproject.toml
  • .github/workflows/ci.yml
  • pyproject.toml
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-14T05:27:49.321Z
Learning: Create a focused branch from `develop` and open pull requests into `develop`, unless a maintainer directs the contributor to target a release branch.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-14T05:27:49.321Z
Learning: Address review feedback until required checks, code-owner review, and review-thread resolution pass before merge.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-14T05:27:49.321Z
Learning: All contributors must sign off their commits using the Developer's Certificate of Origin, for example with `git commit -s -m "Your message"`.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-14T05:27:49.321Z
Learning: Contributions must satisfy the Developer's Certificate of Origin 1.1: the contributor must have the right to submit the work under the applicable open-source license, and acknowledges that contribution and sign-off records are public and retained indefinitely.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-14T05:27:53.553Z
Learning: Use the documented `uv` commands to install dependencies and run the main project or MCP project tests.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-14T05:27:53.553Z
Learning: Refer to each benchmark's README for benchmark-specific instructions and consult the customization guide when adding evaluation harnesses.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-14T05:27:53.553Z
Learning: Use verbose CLI logging, Phoenix tracing, and the documented troubleshooting steps when debugging.
🪛 ast-grep (0.44.1)
mcp/scripts/check_runtime_dependencies.py

[info] 134-134: use jsonify instead of json.dumps for JSON output
Context: json.dumps(result, sort_keys=True)
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)

mcp/tests/test_server_runtime.py

[warning] 1034-1034: Configuring an LLM/agent client endpoint over http:// sends prompts and responses (and often API keys) in cleartext, exposing them to interception. Use https for the base_url.
Context: base_url="http://localhost"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(llm-client-insecure-http-python)


[warning] 1083-1083: Configuring an LLM/agent client endpoint over http:// sends prompts and responses (and often API keys) in cleartext, exposing them to interception. Use https for the base_url.
Context: base_url="http://localhost"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(llm-client-insecure-http-python)


[warning] 1158-1158: Configuring an LLM/agent client endpoint over http:// sends prompts and responses (and often API keys) in cleartext, exposing them to interception. Use https for the base_url.
Context: base_url="http://localhost"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(llm-client-insecure-http-python)


[warning] 1202-1202: Configuring an LLM/agent client endpoint over http:// sends prompts and responses (and often API keys) in cleartext, exposing them to interception. Use https for the base_url.
Context: base_url="http://localhost"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(llm-client-insecure-http-python)

🪛 OpenGrep (1.25.0)
mcp/src/aiq_mcp/job_store.py

[ERROR] 166-181: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)

🪛 SkillSpector (2.3.11)
.agents/skills/aiq-release-qa/SKILL.md

[error] 112: [PE3] Credential Access: Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Remediation: Remove references to credential paths. Use environment variables or secrets managers. For docs, use placeholder paths (e.g., /path/to/config). Never load .env or token files in production code paths.

(Privilege Escalation (PE3))


[error] 112: [PE3] Credential Access: Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Remediation: Remove references to credential paths. Use environment variables or secrets managers. For docs, use placeholder paths (e.g., /path/to/config). Never load .env or token files in production code paths.

(Privilege Escalation (PE3))


[error] 112: [PE3] Credential Access: Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Remediation: Remove references to credential paths. Use environment variables or secrets managers. For docs, use placeholder paths (e.g., /path/to/config). Never load .env or token files in production code paths.

(Privilege Escalation (PE3))

🔇 Additional comments (59)
LICENSE-THIRD-PARTY (1)

8-11: LGTM!

docs/source/get-started/installation.md (1)

15-15: LGTM!

Also applies to: 49-49

CONTRIBUTING.md (1)

32-42: LGTM!

scripts/setup.sh (3)

6-38: LGTM!


65-74: LGTM!

Also applies to: 89-98


169-170: LGTM!

mcp/REFERENCE_PARITY.md (2)

1-75: LGTM!


76-84: 📐 Maintainability & Code Quality

mcp/tests/test_workflow_runner.py exists, so this reference is valid.

			> Likely an incorrect or invalid review comment.
frontends/aiq_api/src/aiq_api/jobs/runner.py (1)

872-888: LGTM!

mcp/src/aiq_mcp/job_store.py (5)

1-106: LGTM!


107-183: LGTM!


184-234: LGTM!


275-358: LGTM!


359-393: LGTM!

mcp/README.md (2)

1-179: LGTM! The rest of the documentation (component layout, anonymous capability model, Host/Origin/CORS guidance, dependency isolation, container deployment) is internally consistent and matches the coding guidelines for scoping cryptography==48.0.1 to mcp/.


34-36: 🎯 Functional Correctness

No issue: GET /mcp is explicitly rejected The app routes self.settings.path to a handler that returns 405 with Allow: POST, so the README matches the implementation.

			> Likely an incorrect or invalid review comment.
.coderabbit.yaml (1)

99-99: LGTM! Expanding the automation/packaging path glob to cover mcp/pyproject.toml and mcp/uv.lock matches the path instructions for reviewing packaging changes.

docs/source/contributing/code-style.md (1)

24-25: LGTM!

.secrets.baseline (1)

130-138: LGTM!

Also applies to: 348-358

mcp/tests/test_dependency_compatibility.py (1)

26-31: LGTM! The cryptography pin matches the documented mcp/uv.lock override.

mcp/tests/test_checkpoint_todos.py (1)

41-51: LGTM! Including only type(exc).__name__ (not the raw exception message, which could contain the DSN) keeps the skip/warning message free of connection secrets.

mcp/tests/test_postgres_job_store.py (2)

57-67: LGTM!


393-468: LGTM! This test precisely covers the mark_failed_if_queued_or_owned ownership/state contract (queued, self-owned running, foreign-owned running, complete, already-failed), matching the guarded UPDATE predicate in job_store.py.

skills/aiq-research/skill-card.md (1)

33-35: LGTM!

README.md (2)

234-244: LGTM!

Also applies to: 305-326


312-315: 🎯 Functional Correctness

The aiq-mcp-server console script is declared in mcp/pyproject.toml, so the README command is valid.

			> Likely an incorrect or invalid review comment.
deploy/Dockerfile (1)

81-90: LGTM! --no-sources correctly prevents uv from attempting workspace-member discovery for [tool.uv.sources] entries during the --no-deps -e . install, matching the stated rationale.

mcp/Dockerfile (1)

10-57: LGTM! Minimal, well-justified copy set and frozen --no-dev --no-default-groups --no-editable sync for the release closure; the import canary correctly wires AIQ_MCP_CONFIG to the copied config.

.agents/skills/aiq-maintain-ci/SKILL.md (1)

39-52: LGTM!

mcp/tests/test_release_checks.py (1)

176-238: LGTM! These three tests match validate_sbom's actual branch logic (local-source allowlist check vs. public PyPI purl contract vs. final set-equality check).

mcp/scripts/check_license_inventory.py (1)

178-213: LGTM! validate_sbom logic matches the exact test expectations reviewed in mcp/tests/test_release_checks.py.

mcp/tests/test_jobs.py (1)

67-182: LGTM! Solid coverage of claim/cancellation races, heartbeat retry, and log/error redaction — verified against the real JobManager/JobStore contracts referenced in this review's graph context.

Also applies to: 665-1172

AGENTS.md (1)

43-43: LGTM!

Also applies to: 55-61

tests/aiq_agent/jobs/test_runner.py (1)

886-894: LGTM!

mcp/tests/test_deployment_assets.py (1)

16-16: LGTM!

Also applies to: 38-50, 62-88, 91-96

.agents/skills/aiq-maintain-ci/references/workflows-and-hooks.md (1)

13-19: LGTM!

Also applies to: 38-51

.agents/skills/aiq-release-qa/references/validation-matrix.md (1)

13-19: LGTM!

Also applies to: 50-62

pyproject.toml (2)

184-185: LGTM!


50-50: 🗄️ Data Integrity & Integration | ⚡ Quick win

Root cryptography constraint: verify [project].dependencies vs. [tool.uv.override-dependencies] and documentation. The change summary says pyproject.toml's direct cryptography dependency moved to >=48.0.1,<49, but the shown override-dependencies still pins >=46.0.6,<47, and AGENTS.md documents the root staying on <47. Since uv's override-dependencies forces the resolved version regardless of the direct dependency declaration, either the bump is a no-op that should be removed/reverted, or the override needs to be updated and the docs are now stale.

  • pyproject.toml#L50-L50: confirm whether the [project].dependencies cryptography bump to >=48.0.1,<49 is intentional; if so, update or remove the conflicting >=46.0.6,<47 entry in [tool.uv.override-dependencies] so the direct dependency isn't silently overridden.
  • AGENTS.md#L105-L109: update the documented root cryptography range if the intended behavior changes, or leave as-is once pyproject.toml is confirmed to still resolve to <47 in practice.

Source: Coding guidelines

mcp/tests/test_server_runtime.py (1)

163-249: LGTM!

Also applies to: 299-300, 925-943, 977-1222

mcp/src/aiq_mcp/jobs.py (1)

211-232: LGTM! Confirms the previously flagged heartbeat-retry issue is fixed, and the cancellation/failure-persistence paths correctly rely on guarded state-conditioned store writes to avoid clobbering already-terminal jobs.

Also applies to: 317-325, 368-424

.agents/skills/aiq-release-qa/SKILL.md (2)

111-112: Static-analysis false positive.

The "credential access" flag on the deploy/.env reference is a false positive — this is a doc instructing contributors how to invoke nat eval with dotenv, not code that reads/logs a secret file.


38-41: LGTM!

Also applies to: 72-88, 104-108

mcp/scripts/check_runtime_dependencies.py (2)

134-134: Static-analysis false positive.

The "use jsonify instead of json.dumps" hint doesn't apply — this is a standalone CLI script printing to stdout, not a web response body.


108-138: LGTM!

mcp/tests/test_runtime_dependencies.py (1)

80-119: LGTM!

scripts/dev.sh (1)

6-13: LGTM!

Also applies to: 61-61

mcp/tests/test_imports.py (1)

32-41: LGTM!

.github/workflows/ci.yml (2)

249-256: 🔒 Security & Privacy

Confirm the ignored advisory is still unresolved and scoped correctly.

GHSA-f4j7-r4q5-qw2c is suppressed via --ignore-until-fixed, which auto-reinstates the gate once a fix ships. Worth a periodic sanity check (or a tracked follow-up) that this advisory still applies to a real dependency in mcp/uv.lock and hasn't been superseded/fixed, since GitHub's advisory record for this ID shows no associated ecosystem package.


37-53: LGTM!

Also applies to: 67-85, 99-119, 120-139, 140-165, 187-237, 257-321

mcp/tests/test_client_session_integration.py (2)

443-446: 🔒 Security & Privacy

Previously flagged raw-exception-in-message issue is fixed here (type(exc).__name__ instead of exc).


133-140: LGTM!

docs/source/contributing/testing.md (1)

10-17: LGTM!

.pre-commit-config.yaml (1)

25-31: LGTM!

Also applies to: 61-66, 78-89

mcp/SECURITY.md (1)

6-133: LGTM!

docs/source/integration/mcp-server.md (1)

18-274: LGTM!

docs/source/deployment/docker-build.md (1)

39-73: LGTM!

mcp/tests/test_config_and_packaging.py (1)

158-224: LGTM!

mcp/pyproject.toml (1)

59-77: 🔒 Security & Privacy

Keep the current prerelease policy. mcp/SECURITY.md already documents prerelease-aware resolution as part of the MCP release profile, and the defusedxml cap exists specifically because of that policy. tornado>=6.5.5 can stay open if that release line is meant to float.

			> Likely an incorrect or invalid review comment.

Comment thread .github/workflows/ci.yml
Comment thread docs/source/contributing/pr-workflow.md
Comment thread mcp/scripts/check_license_inventory.py
Comment thread mcp/src/aiq_mcp/server.py

@AjayThorve AjayThorve left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review against the current head, including an isolated release-container run with the credentials from deploy/.env.

The unit/protocol suites and image build are green, but the credentialed shallow and deep paths both returned generic error text while the MCP ledger reported state="complete". The inline comments cover that state-contract failure, the standalone shallow runtime failure, retention leakage, duplicate classification, the non-installable wheel, the dropped Compose setting, and the missing report-follow-up surface.

GitHub also currently reports this head as CONFLICTING / DIRTY against develop (.secrets.baseline, README.md, and uv.lock), so the checks need to be rerun after the branch is updated.

Comment thread mcp/src/aiq_mcp/jobs.py Outdated
Comment thread mcp/pyproject.toml
Comment thread mcp/src/aiq_mcp/job_store.py Outdated
Comment thread mcp/src/aiq_mcp/jobs.py
Comment thread mcp/pyproject.toml
Comment thread deploy/compose/docker-compose.mcp.yaml
Comment thread mcp/REFERENCE_PARITY.md
@AjayThorve AjayThorve changed the base branch from develop to release/2.2 July 14, 2026 07:11
tanleach added 12 commits July 14, 2026 10:19
Add an anonymous MCP transport for submitting and polling AI-Q
research jobs, backed by PostgreSQL. Include deployment assets,
documentation, compatibility tests, release checks, and CI gates.

Signed-off-by: Tanner Leach <tleach@nvidia.com>
Require NLTK 3.10, constrain its new defusedxml dependency to the stable
0.7 release line, and refresh the lockfile.

Remove the resolved NLTK vulnerability exceptions from the MCP audit gate
and update the release security documentation.

Signed-off-by: Tanner Leach <tleach@nvidia.com>
Signed-off-by: Tanner Leach <tleach@nvidia.com>
Sanitize captured workflow failures before returning them through public MCP
poll/final-report responses, and guard async job state transitions by current
state and runner ownership to avoid stale background tasks overwriting terminal
rows.

Signed-off-by: Tanner Leach <tleach@nvidia.com>
Move the MCP server into an opt-in dependency group and select it in
CI, setup, pre-commit, and full-suite validation paths.

Keep the main AI-Q Docker build independent of absent MCP workspace
sources, and add regression coverage and updated usage documentation.

Signed-off-by: Tanner Leach <tleach@nvidia.com>
- split MCP from the root uv workspace and add its own lock
- keep cryptography 48 limited to the audited MCP release profile
- route CI, Docker, SBOM, tests, and docs through the MCP project

Signed-off-by: Tanner Leach <tleach@nvidia.com>
Retry heartbeat writes after transient store failures without exposing
internal exception details.

Ensure heartbeat task failures cannot skip job context and failure-capture
cleanup.

Signed-off-by: Tanner Leach <tleach@nvidia.com>
Require uv 0.11.25 or newer for scoped dependency overrides and make
setup reject unsupported versions before environment creation.

Align the documentation and packaging contracts, and correct the import
boundary assertion for the isolated MCP environment.

Signed-off-by: Tanner Leach <tleach@nvidia.com>
Sanitize submission, polling, and report infrastructure exceptions before
FastMCP serializes them.

Preserve the original queued capability when an inline wait fails, add
transport-level sentinel coverage, and document the stable failure contract.

Signed-off-by: Tanner Leach <tleach@nvidia.com>
Validate queued submit response fields before inline waits so malformed job data returns a public MCP error without exposing internal details.

Signed-off-by: Tanner Leach <tleach@nvidia.com>
Pin the MCP PostgreSQL service image and release artifact uploads to
immutable references.

Avoid exposing raw PostgreSQL connection errors from integration-test
fixtures.

Signed-off-by: Tanner Leach <tleach@nvidia.com>
Guard failure persistence so queued jobs and running jobs owned by the
current runner can transition to failed without overwriting terminal or
foreign-owned work.

Keep shallow submissions pollable if a local task exits with a
nonterminal row, and cover claim and cancellation races in unit and
PostgreSQL tests.

Signed-off-by: Tanner Leach <tleach@nvidia.com>
The job runner now persists only the exception class name instead of raw
exception text, so the encrypted event-flush failure test must assert the
sanitized error message rather than the injected RuntimeError text.

Signed-off-by: Tanner Leach <tleach@nvidia.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/aiq_agent/knowledge/summary_store.py (1)

141-154: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Restore the redacted engine identity in the dispose-failure warning.

Line 153 now logs only type(e).__name__, dropping the _redact_db_url(key) reference that the success-path log (line 151) still includes right above it. Since the key was already going through _redact_db_url, re-adding it costs nothing and restores the ability to tell which cached engine failed to dispose.

🔧 Proposed fix
                 except Exception as e:
-                    logger.warning("Failed to dispose engine (%s)", type(e).__name__)
+                    logger.warning("Failed to dispose engine for %s (%s)", _redact_db_url(key), type(e).__name__)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/aiq_agent/knowledge/summary_store.py` around lines 141 - 154, Update the
exception warning in _cleanup_stale_engines to include the redacted engine
identity via _redact_db_url(key), while retaining the exception type and
existing success-path behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@mcp/README.md`:
- Line 81: Document the AIQ_MCP_MAX_QUERY_CHARS setting in both configuration
tables in mcp/README.md, including its tested default value of 8000 and a
concise description consistent with the surrounding entries. Do not alter the
existing settings.
- Around line 79-80: Update the environment-variable defaults table in the MCP
README to explicitly mark the configs/config_mcp.yml and deploy/.env defaults
for AIQ_MCP_CONFIG and AIQ_MCP_ENV_FILE as source-checkout-only. Clarify that
installed-package or wheel usage does not receive these paths by default and
must provide AIQ_MCP_CONFIG as required.

In `@mcp/REFERENCE_PARITY.md`:
- Line 26: Update the tool-surface freeze documentation and parity definition to
account for report follow-up capabilities such as report_ask and report_edit,
either by including them in the frozen surface or by documenting the intentional
product gap and planned release. Ensure the SHA-256 parity hash and the stated
tool ordering/schema remain consistent with the chosen surface.

In `@mcp/scripts/check_license_inventory.py`:
- Line 1: Add test coverage for validate_lock_sources by exposing it through the
_NAMESPACE setup in test_release_checks.py and exercising a temporary lock file
with the exact approved local-source set, an unapproved registry source, and a
non-string or malformed editable value. Ensure the accepted fixture explicitly
verifies whether the aiq-agent "../" versus ".." path normalization is handled
correctly, without changing validate_lock_sources unless the test demonstrates
an actual path-matching defect.

In `@mcp/scripts/protocol_smoke.py`:
- Around line 29-33: Update _health_url to reject endpoint URLs containing
userinfo or query parameters (and fragments) before constructing the health URL,
preserving only valid absolute HTTP/HTTPS URLs without credentials or tokens.
Ensure the smoke-test output path around the endpoint handling also does not
echo the original credential-bearing URL or expose secret values.

In `@mcp/src/aiq_mcp/job_store.py`:
- Around line 235-273: Update JobStore.get to require a principal argument and
constrain its query with both job_id and principal. In record_poll, pass the
provided principal to the fallback get call so failed principal-scoped updates
cannot return another principal’s job data.

In `@mcp/src/aiq_mcp/jobs.py`:
- Around line 60-135: Replace MCP-layer inference in _WorkflowFailureCapture and
_run_job with a structured terminal outcome emitted by the workflow boundary,
containing success or failed status and a stable public error for every
swallowed research failure. Persist that outcome directly so fallback responses
cannot be saved as state="complete"; remove reliance on _CAPTURED_EXCEPTIONS and
log-message substring matching.
- Line 241: Remove the duplicate classification between submit() and
WorkflowRunner.run_query(): make one component own the classifier result and
thread that decision through _run_job into the workflow instead of invoking
intent_classifier again. Ensure the persisted depth and duration correspond to
the route actually executed, and add a test covering that consistency for a
non-deterministic classifier.

In `@mcp/src/aiq_mcp/workflow_runner.py`:
- Around line 62-88: The _close_owned_checkpointers method relies on private
aiq_agent.common cache names and silently skips cleanup when they are absent.
Replace this dependency with a public checkpointer cleanup or iteration API; if
no such API exists, detect missing _checkpointers or _postgres_pools and emit a
warning before handling cleanup, while preserving ownership-based removal and
closing behavior.

In `@mcp/tests/test_postgres_job_store.py`:
- Around line 651-655: Update the _reset_schema helper to validate db_url before
opening the connection or executing DROP statements, and fail closed unless the
target database is the CI/test database named aiq_mcp_tests. Keep the
destructive reset behavior unchanged for that explicitly allowed database and
reject all other targets.

---

Outside diff comments:
In `@src/aiq_agent/knowledge/summary_store.py`:
- Around line 141-154: Update the exception warning in _cleanup_stale_engines to
include the redacted engine identity via _redact_db_url(key), while retaining
the exception type and existing success-path behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 2b17bbf0-40af-4bb1-bc97-c57b368ebf32

📥 Commits

Reviewing files that changed from the base of the PR and between 05882bf and df763f4.

⛔ Files ignored due to path filters (2)
  • mcp/uv.lock is excluded by !**/*.lock
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (69)
  • .agents/skills/aiq-maintain-ci/SKILL.md
  • .agents/skills/aiq-maintain-ci/references/workflows-and-hooks.md
  • .agents/skills/aiq-release-qa/SKILL.md
  • .agents/skills/aiq-release-qa/references/validation-matrix.md
  • .coderabbit.yaml
  • .dockerignore
  • .github/workflows/ci.yml
  • .pre-commit-config.yaml
  • .secrets.baseline
  • AGENTS.md
  • CONTRIBUTING.md
  • LICENSE-THIRD-PARTY
  • README.md
  • configs/config_mcp.yml
  • deploy/Dockerfile
  • deploy/compose/docker-compose.mcp.yaml
  • docs/source/contributing/code-style.md
  • docs/source/contributing/pr-workflow.md
  • docs/source/contributing/testing.md
  • docs/source/deployment/docker-build.md
  • docs/source/get-started/installation.md
  • docs/source/index.md
  • docs/source/integration/index.md
  • docs/source/integration/mcp-server.md
  • frontends/aiq_api/src/aiq_api/jobs/runner.py
  • mcp/Dockerfile
  • mcp/LICENSE
  • mcp/README.md
  • mcp/REFERENCE_PARITY.md
  • mcp/SECURITY.md
  • mcp/deploy/README.md
  • mcp/deploy/init-mcp-db.sql
  • mcp/pyproject.toml
  • mcp/scripts/check_license_inventory.py
  • mcp/scripts/check_runtime_dependencies.py
  • mcp/scripts/protocol_smoke.py
  • mcp/src/aiq_mcp/__init__.py
  • mcp/src/aiq_mcp/checkpoint_todos.py
  • mcp/src/aiq_mcp/db_url.py
  • mcp/src/aiq_mcp/job_store.py
  • mcp/src/aiq_mcp/jobs.py
  • mcp/src/aiq_mcp/server.py
  • mcp/src/aiq_mcp/workflow_runner.py
  • mcp/tests/conftest.py
  • mcp/tests/test_checkpoint_todos.py
  • mcp/tests/test_client_session_integration.py
  • mcp/tests/test_config_and_packaging.py
  • mcp/tests/test_db_url.py
  • mcp/tests/test_dependency_compatibility.py
  • mcp/tests/test_deployment_assets.py
  • mcp/tests/test_imports.py
  • mcp/tests/test_job_store.py
  • mcp/tests/test_jobs.py
  • mcp/tests/test_postgres_job_store.py
  • mcp/tests/test_release_checks.py
  • mcp/tests/test_runtime_dependencies.py
  • mcp/tests/test_server_runtime.py
  • mcp/tests/test_workflow_runner.py
  • pyproject.toml
  • scripts/dev.sh
  • scripts/setup.sh
  • skills/aiq-research/skill-card.md
  • src/aiq_agent/agents/chat_researcher/register.py
  • src/aiq_agent/common/logging_utils.py
  • src/aiq_agent/knowledge/summary_store.py
  • tests/aiq_agent/agents/chat_researcher/test_register_helpers.py
  • tests/aiq_agent/common/test_logging_utils.py
  • tests/aiq_agent/jobs/test_runner.py
  • tests/knowledge_layer_tests/test_summary_store.py
📜 Review details
⏰ Context from checks skipped due to timeout. (2)
  • GitHub Check: Run Harbor skill eval
  • GitHub Check: Pytest and Coverage
🧰 Additional context used
📓 Path-based instructions (16)
**/*.{py,ts,tsx,js,jsx,yml,yaml,json,env,md}

📄 CodeRabbit inference engine (AGENTS.md)

Never commit secrets, tokens, or environment-specific hostnames; use environment variables and SecretStr, and resolve API keys at runtime.

Files:

  • docs/source/integration/index.md
  • mcp/src/aiq_mcp/__init__.py
  • skills/aiq-research/skill-card.md
  • docs/source/index.md
  • mcp/tests/conftest.py
  • mcp/tests/test_db_url.py
  • mcp/deploy/README.md
  • mcp/tests/test_job_store.py
  • docs/source/get-started/installation.md
  • mcp/tests/test_dependency_compatibility.py
  • AGENTS.md
  • tests/aiq_agent/agents/chat_researcher/test_register_helpers.py
  • mcp/REFERENCE_PARITY.md
  • mcp/src/aiq_mcp/db_url.py
  • docs/source/contributing/code-style.md
  • CONTRIBUTING.md
  • tests/aiq_agent/common/test_logging_utils.py
  • configs/config_mcp.yml
  • tests/aiq_agent/jobs/test_runner.py
  • docs/source/contributing/pr-workflow.md
  • mcp/README.md
  • docs/source/deployment/docker-build.md
  • mcp/tests/test_imports.py
  • deploy/compose/docker-compose.mcp.yaml
  • frontends/aiq_api/src/aiq_api/jobs/runner.py
  • tests/knowledge_layer_tests/test_summary_store.py
  • README.md
  • mcp/scripts/check_runtime_dependencies.py
  • src/aiq_agent/common/logging_utils.py
  • docs/source/contributing/testing.md
  • mcp/src/aiq_mcp/workflow_runner.py
  • mcp/SECURITY.md
  • mcp/tests/test_checkpoint_todos.py
  • src/aiq_agent/agents/chat_researcher/register.py
  • src/aiq_agent/knowledge/summary_store.py
  • mcp/tests/test_deployment_assets.py
  • mcp/tests/test_workflow_runner.py
  • mcp/tests/test_client_session_integration.py
  • mcp/tests/test_config_and_packaging.py
  • mcp/tests/test_jobs.py
  • mcp/tests/test_postgres_job_store.py
  • mcp/scripts/protocol_smoke.py
  • mcp/tests/test_server_runtime.py
  • mcp/tests/test_runtime_dependencies.py
  • mcp/src/aiq_mcp/server.py
  • mcp/src/aiq_mcp/checkpoint_todos.py
  • docs/source/integration/mcp-server.md
  • mcp/src/aiq_mcp/job_store.py
  • mcp/scripts/check_license_inventory.py
  • mcp/tests/test_release_checks.py
  • mcp/src/aiq_mcp/jobs.py
docs/source/**/*

📄 CodeRabbit inference engine (AGENTS.md)

Update canonical documentation under docs/source/ when behavior, configuration, or workflows change; do not duplicate full documentation pages into skills.

Files:

  • docs/source/integration/index.md
  • docs/source/index.md
  • docs/source/get-started/installation.md
  • docs/source/contributing/code-style.md
  • docs/source/contributing/pr-workflow.md
  • docs/source/deployment/docker-build.md
  • docs/source/contributing/testing.md
  • docs/source/integration/mcp-server.md
**/*

📄 CodeRabbit inference engine (AGENTS.md)

**/*: Keep changes scoped to this repository and avoid editing adjacent repositories; treat each sources/* package as independent and prefer the smallest package-local change.
Run the narrowest relevant validation command first, broadening to the full suite only when a change crosses shared boundaries.
For substantial behavior, authentication, UI, or architecture changes, open a design discussion before coding.
Keep pull requests scoped: avoid unrelated files, accidental generated artifacts, and secrets, and provide validation evidence with commands and results.
Every commit must be signed off with git commit -s; commits must contain a Signed-off-by trailer.
Load the relevant task-specific maintainer skill from .agents/skills/ before starting a workflow it covers; API-consumer skills under skills/ are a separate audience.

Files:

  • docs/source/integration/index.md
  • mcp/LICENSE
  • mcp/src/aiq_mcp/__init__.py
  • skills/aiq-research/skill-card.md
  • LICENSE-THIRD-PARTY
  • docs/source/index.md
  • mcp/tests/conftest.py
  • mcp/tests/test_db_url.py
  • mcp/deploy/README.md
  • deploy/Dockerfile
  • mcp/tests/test_job_store.py
  • docs/source/get-started/installation.md
  • mcp/tests/test_dependency_compatibility.py
  • AGENTS.md
  • tests/aiq_agent/agents/chat_researcher/test_register_helpers.py
  • mcp/REFERENCE_PARITY.md
  • mcp/src/aiq_mcp/db_url.py
  • docs/source/contributing/code-style.md
  • CONTRIBUTING.md
  • scripts/dev.sh
  • tests/aiq_agent/common/test_logging_utils.py
  • configs/config_mcp.yml
  • tests/aiq_agent/jobs/test_runner.py
  • mcp/deploy/init-mcp-db.sql
  • docs/source/contributing/pr-workflow.md
  • mcp/README.md
  • docs/source/deployment/docker-build.md
  • mcp/tests/test_imports.py
  • deploy/compose/docker-compose.mcp.yaml
  • frontends/aiq_api/src/aiq_api/jobs/runner.py
  • tests/knowledge_layer_tests/test_summary_store.py
  • README.md
  • mcp/Dockerfile
  • mcp/scripts/check_runtime_dependencies.py
  • src/aiq_agent/common/logging_utils.py
  • scripts/setup.sh
  • docs/source/contributing/testing.md
  • mcp/src/aiq_mcp/workflow_runner.py
  • mcp/SECURITY.md
  • mcp/tests/test_checkpoint_todos.py
  • src/aiq_agent/agents/chat_researcher/register.py
  • src/aiq_agent/knowledge/summary_store.py
  • mcp/pyproject.toml
  • mcp/tests/test_deployment_assets.py
  • mcp/tests/test_workflow_runner.py
  • pyproject.toml
  • mcp/tests/test_client_session_integration.py
  • mcp/tests/test_config_and_packaging.py
  • mcp/tests/test_jobs.py
  • mcp/tests/test_postgres_job_store.py
  • mcp/scripts/protocol_smoke.py
  • mcp/tests/test_server_runtime.py
  • mcp/tests/test_runtime_dependencies.py
  • mcp/src/aiq_mcp/server.py
  • mcp/src/aiq_mcp/checkpoint_todos.py
  • docs/source/integration/mcp-server.md
  • mcp/src/aiq_mcp/job_store.py
  • mcp/scripts/check_license_inventory.py
  • mcp/tests/test_release_checks.py
  • mcp/src/aiq_mcp/jobs.py
{docs/**,README.md,CONTRIBUTING.md,SECURITY.md,CODE-OF-CONDUCT.md}

⚙️ CodeRabbit configuration file

{docs/**,README.md,CONTRIBUTING.md,SECURITY.md,CODE-OF-CONDUCT.md}: Review documentation for command accuracy, branch-name consistency, current CI and copy-pr-bot behavior, public
vs internal boundary clarity, stale examples, and links that no longer match the repository layout.

Files:

  • docs/source/integration/index.md
  • docs/source/index.md
  • docs/source/get-started/installation.md
  • docs/source/contributing/code-style.md
  • CONTRIBUTING.md
  • docs/source/contributing/pr-workflow.md
  • docs/source/deployment/docker-build.md
  • README.md
  • docs/source/contributing/testing.md
  • docs/source/integration/mcp-server.md
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Format and lint Python with Ruff using the repository’s configuration: line length 120, target Python 3.11, rules E/F/W/I/PL/UP, and single-line imports.
Never print or log secret values, including in tool output or error messages.
Missing-secret paths must degrade gracefully by stubbing or skipping rather than crashing or leaking values.

For Python changes, run uv run ruff check ., uv run ruff format --check ., and uv run pytest as applicable.

Files:

  • mcp/src/aiq_mcp/__init__.py
  • mcp/tests/conftest.py
  • mcp/tests/test_db_url.py
  • mcp/tests/test_job_store.py
  • mcp/tests/test_dependency_compatibility.py
  • tests/aiq_agent/agents/chat_researcher/test_register_helpers.py
  • mcp/src/aiq_mcp/db_url.py
  • tests/aiq_agent/common/test_logging_utils.py
  • tests/aiq_agent/jobs/test_runner.py
  • mcp/tests/test_imports.py
  • frontends/aiq_api/src/aiq_api/jobs/runner.py
  • tests/knowledge_layer_tests/test_summary_store.py
  • mcp/scripts/check_runtime_dependencies.py
  • src/aiq_agent/common/logging_utils.py
  • mcp/src/aiq_mcp/workflow_runner.py
  • mcp/tests/test_checkpoint_todos.py
  • src/aiq_agent/agents/chat_researcher/register.py
  • src/aiq_agent/knowledge/summary_store.py
  • mcp/tests/test_deployment_assets.py
  • mcp/tests/test_workflow_runner.py
  • mcp/tests/test_client_session_integration.py
  • mcp/tests/test_config_and_packaging.py
  • mcp/tests/test_jobs.py
  • mcp/tests/test_postgres_job_store.py
  • mcp/scripts/protocol_smoke.py
  • mcp/tests/test_server_runtime.py
  • mcp/tests/test_runtime_dependencies.py
  • mcp/src/aiq_mcp/server.py
  • mcp/src/aiq_mcp/checkpoint_todos.py
  • mcp/src/aiq_mcp/job_store.py
  • mcp/scripts/check_license_inventory.py
  • mcp/tests/test_release_checks.py
  • mcp/src/aiq_mcp/jobs.py
**/*.{py,ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Validate UI-affecting changes with npm run lint, npm run type-check, and npm run test:ci; include a screenshot for visible changes.

Files:

  • mcp/src/aiq_mcp/__init__.py
  • mcp/tests/conftest.py
  • mcp/tests/test_db_url.py
  • mcp/tests/test_job_store.py
  • mcp/tests/test_dependency_compatibility.py
  • tests/aiq_agent/agents/chat_researcher/test_register_helpers.py
  • mcp/src/aiq_mcp/db_url.py
  • tests/aiq_agent/common/test_logging_utils.py
  • tests/aiq_agent/jobs/test_runner.py
  • mcp/tests/test_imports.py
  • frontends/aiq_api/src/aiq_api/jobs/runner.py
  • tests/knowledge_layer_tests/test_summary_store.py
  • mcp/scripts/check_runtime_dependencies.py
  • src/aiq_agent/common/logging_utils.py
  • mcp/src/aiq_mcp/workflow_runner.py
  • mcp/tests/test_checkpoint_todos.py
  • src/aiq_agent/agents/chat_researcher/register.py
  • src/aiq_agent/knowledge/summary_store.py
  • mcp/tests/test_deployment_assets.py
  • mcp/tests/test_workflow_runner.py
  • mcp/tests/test_client_session_integration.py
  • mcp/tests/test_config_and_packaging.py
  • mcp/tests/test_jobs.py
  • mcp/tests/test_postgres_job_store.py
  • mcp/scripts/protocol_smoke.py
  • mcp/tests/test_server_runtime.py
  • mcp/tests/test_runtime_dependencies.py
  • mcp/src/aiq_mcp/server.py
  • mcp/src/aiq_mcp/checkpoint_todos.py
  • mcp/src/aiq_mcp/job_store.py
  • mcp/scripts/check_license_inventory.py
  • mcp/tests/test_release_checks.py
  • mcp/src/aiq_mcp/jobs.py
mcp/**/*.py

📄 CodeRabbit inference engine (CONTRIBUTING.md)

For changes under mcp/, run the MCP project's development setup and uv run --project mcp --extra dev pytest mcp/tests.

Files:

  • mcp/src/aiq_mcp/__init__.py
  • mcp/tests/conftest.py
  • mcp/tests/test_db_url.py
  • mcp/tests/test_job_store.py
  • mcp/tests/test_dependency_compatibility.py
  • mcp/src/aiq_mcp/db_url.py
  • mcp/tests/test_imports.py
  • mcp/scripts/check_runtime_dependencies.py
  • mcp/src/aiq_mcp/workflow_runner.py
  • mcp/tests/test_checkpoint_todos.py
  • mcp/tests/test_deployment_assets.py
  • mcp/tests/test_workflow_runner.py
  • mcp/tests/test_client_session_integration.py
  • mcp/tests/test_config_and_packaging.py
  • mcp/tests/test_jobs.py
  • mcp/tests/test_postgres_job_store.py
  • mcp/scripts/protocol_smoke.py
  • mcp/tests/test_server_runtime.py
  • mcp/tests/test_runtime_dependencies.py
  • mcp/src/aiq_mcp/server.py
  • mcp/src/aiq_mcp/checkpoint_todos.py
  • mcp/src/aiq_mcp/job_store.py
  • mcp/scripts/check_license_inventory.py
  • mcp/tests/test_release_checks.py
  • mcp/src/aiq_mcp/jobs.py
{skills/**,.agents/skills/**,.claude/skills/**,.github/skill-eval/**}

⚙️ CodeRabbit configuration file

{skills/**,.agents/skills/**,.claude/skills/**,.github/skill-eval/**}: Review Agent Skill and skill-eval changes for valid skill metadata, deterministic eval specs, safe handling of
credentials, and clear generated-output boundaries. Do not flag SKILL.md files for missing SPDX headers when the
entrypoint intentionally starts with YAML frontmatter.

Files:

  • skills/aiq-research/skill-card.md
  • .agents/skills/aiq-release-qa/references/validation-matrix.md
  • .agents/skills/aiq-maintain-ci/references/workflows-and-hooks.md
  • .agents/skills/aiq-maintain-ci/SKILL.md
  • .agents/skills/aiq-release-qa/SKILL.md
{deploy/**,configs/**}

⚙️ CodeRabbit configuration file

{deploy/**,configs/**}: Review deployment and config changes for secret separation, safe defaults, local-vs-production behavior, Helm and
Docker portability, and documentation parity. Flag committed credentials, environment-specific NVIDIA internals in
public defaults, and changes that make examples diverge from CI-tested paths.

Files:

  • deploy/Dockerfile
  • configs/config_mcp.yml
  • deploy/compose/docker-compose.mcp.yaml
configs/**/*.y{a,}ml

📄 CodeRabbit inference engine (AGENTS.md)

Use _type names derived from the registered configuration class for NAT YAML configuration schemas.

Files:

  • configs/config_mcp.yml
**/*.{yaml,yml}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

For deployment changes, run the relevant Helm or Compose validation and describe the environment used.

Files:

  • configs/config_mcp.yml
  • deploy/compose/docker-compose.mcp.yaml
{src/aiq_agent/fastapi_extensions/**,frontends/aiq_api/src/aiq_api/**}

⚙️ CodeRabbit configuration file

{src/aiq_agent/fastapi_extensions/**,frontends/aiq_api/src/aiq_api/**}: Treat API, auth, and job-runner changes as externally visible contracts. Check authorization boundaries,
request tracing, async job lifecycle, websocket reconnect behavior, error responses, and cross-user data isolation.
Require tests for route behavior, access decisions, and job state transitions when those surfaces change.

Files:

  • frontends/aiq_api/src/aiq_api/jobs/runner.py
src/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.py: Respect authenticated data sources: honor requires_auth, pass through per-user tokens, use backend token validators, and apply owner guardrails before loading protected report or artifact context into an agent.
Do not weaken or bypass AuthMiddleware, token validators, or authentication gating without prior design discussion.

Files:

  • src/aiq_agent/common/logging_utils.py
  • src/aiq_agent/agents/chat_researcher/register.py
  • src/aiq_agent/knowledge/summary_store.py
{.github/**,ci/**,.pre-commit-config.yaml,pyproject.toml,uv.lock,mcp/pyproject.toml,mcp/uv.lock}

⚙️ CodeRabbit configuration file

{.github/**,ci/**,.pre-commit-config.yaml,pyproject.toml,uv.lock,mcp/pyproject.toml,mcp/uv.lock}: Review automation and packaging changes for least-privilege permissions, pinned versions where appropriate,
copy-pr-bot pull-request/ branch behavior, reproducible uv/npm setup, secret handling, and consistency with
the documented validation matrix.

Files:

  • .pre-commit-config.yaml
  • mcp/pyproject.toml
  • pyproject.toml
  • .github/workflows/ci.yml
src/aiq_agent/agents/**/*

⚙️ CodeRabbit configuration file

src/aiq_agent/agents/**/*: Review agent changes for research workflow correctness, graph state transitions, prompt/tool contracts,
HITL behavior, and failure handling. Flag changes that weaken source attribution, report generation,
async cancellation, checkpointing, or data-source selection without focused tests and docs.

Files:

  • src/aiq_agent/agents/chat_researcher/register.py
{src/aiq_agent/knowledge/**,sources/**}

⚙️ CodeRabbit configuration file

{src/aiq_agent/knowledge/**,sources/**}: Review data-source and knowledge-layer changes for optional dependency boundaries, external API error handling,
retry/rate-limit behavior, deterministic tests, and registration consistency. New source packages should include
package metadata, plugin registration when applicable, and source-level tests.

Files:

  • src/aiq_agent/knowledge/summary_store.py
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-14T14:40:53.280Z
Learning: Search existing issues and pull requests before opening new work.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-14T14:40:53.280Z
Learning: Open an issue or discussion before making large design changes, public API changes, deployment changes, or contributor workflow changes.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-14T14:40:53.280Z
Learning: Do not include secrets, credentials, private hostnames, internal-only logs, customer data, or generated local artifacts in contributions.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-14T14:40:53.280Z
Learning: Target the `develop` branch unless a maintainer directs use of a release branch.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-14T14:40:53.280Z
Learning: Keep changes focused and add or update tests for behavior changes.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-14T14:40:53.280Z
Learning: Sign off every commit with `git commit -s`.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-14T14:40:53.280Z
Learning: Run relevant local validation before opening a pull request and include exact validation output or a workflow link.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-14T14:40:53.280Z
Learning: Pull requests must target `develop`, use the PR template with exact validation evidence, and satisfy required checks, code-owner review, resolved review threads, and branch policy before merge.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-14T14:40:53.280Z
Learning: Contributors must ensure their contribution is original or appropriately licensed and that they have the right to submit it under the project's license.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-14T14:40:56.506Z
Learning: Run `pre-commit run --all-files` or the repository's `./scripts/dev.sh pre-commit` workflow before submitting changes; this includes linting, formatting, lock checks, secret detection, notebook output clearing, and Markdown link validation.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-14T14:41:08.847Z
Learning: Use the documented `uv` commands to install development dependencies, run pytest, generate coverage, or execute an individual test file.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-14T14:41:08.847Z
Learning: Refer to each benchmark's README for benchmark-specific testing details.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-14T14:41:08.847Z
Learning: Use the Customization guide when adding evaluation harnesses.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-14T14:41:08.847Z
Learning: For debugging, use verbose CLI logging, Phoenix tracing, and the documented remedies for common import, authentication, tool, and pre-commit issues.
🪛 ast-grep (0.44.1)
mcp/scripts/check_runtime_dependencies.py

[info] 134-134: use jsonify instead of json.dumps for JSON output
Context: json.dumps(result, sort_keys=True)
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)

mcp/scripts/protocol_smoke.py

[info] 137-137: use jsonify instead of json.dumps for JSON output
Context: json.dumps(result, indent=2, sort_keys=True)
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)

mcp/tests/test_server_runtime.py

[warning] 521-521: Configuring an LLM/agent client endpoint over http:// sends prompts and responses (and often API keys) in cleartext, exposing them to interception. Use https for the base_url.
Context: base_url="http://localhost"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(llm-client-insecure-http-python)


[warning] 588-588: Configuring an LLM/agent client endpoint over http:// sends prompts and responses (and often API keys) in cleartext, exposing them to interception. Use https for the base_url.
Context: base_url="http://localhost"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(llm-client-insecure-http-python)


[warning] 601-601: Configuring an LLM/agent client endpoint over http:// sends prompts and responses (and often API keys) in cleartext, exposing them to interception. Use https for the base_url.
Context: base_url="http://localhost"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(llm-client-insecure-http-python)


[warning] 608-608: Configuring an LLM/agent client endpoint over http:// sends prompts and responses (and often API keys) in cleartext, exposing them to interception. Use https for the base_url.
Context: base_url="http://localhost"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(llm-client-insecure-http-python)


[warning] 670-670: Configuring an LLM/agent client endpoint over http:// sends prompts and responses (and often API keys) in cleartext, exposing them to interception. Use https for the base_url.
Context: base_url="http://localhost"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(llm-client-insecure-http-python)


[warning] 682-682: Configuring an LLM/agent client endpoint over http:// sends prompts and responses (and often API keys) in cleartext, exposing them to interception. Use https for the base_url.
Context: base_url="http://localhost"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(llm-client-insecure-http-python)


[warning] 687-687: Configuring an LLM/agent client endpoint over http:// sends prompts and responses (and often API keys) in cleartext, exposing them to interception. Use https for the base_url.
Context: base_url="http://localhost"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(llm-client-insecure-http-python)


[warning] 703-703: Configuring an LLM/agent client endpoint over http:// sends prompts and responses (and often API keys) in cleartext, exposing them to interception. Use https for the base_url.
Context: base_url="http://localhost"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(llm-client-insecure-http-python)


[warning] 737-737: Configuring an LLM/agent client endpoint over http:// sends prompts and responses (and often API keys) in cleartext, exposing them to interception. Use https for the base_url.
Context: base_url="http://localhost"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(llm-client-insecure-http-python)


[warning] 752-752: Configuring an LLM/agent client endpoint over http:// sends prompts and responses (and often API keys) in cleartext, exposing them to interception. Use https for the base_url.
Context: base_url="http://localhost"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(llm-client-insecure-http-python)


[warning] 763-763: Configuring an LLM/agent client endpoint over http:// sends prompts and responses (and often API keys) in cleartext, exposing them to interception. Use https for the base_url.
Context: base_url="http://untrusted.example"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(llm-client-insecure-http-python)


[warning] 1034-1034: Configuring an LLM/agent client endpoint over http:// sends prompts and responses (and often API keys) in cleartext, exposing them to interception. Use https for the base_url.
Context: base_url="http://localhost"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(llm-client-insecure-http-python)


[warning] 1083-1083: Configuring an LLM/agent client endpoint over http:// sends prompts and responses (and often API keys) in cleartext, exposing them to interception. Use https for the base_url.
Context: base_url="http://localhost"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(llm-client-insecure-http-python)


[warning] 1158-1158: Configuring an LLM/agent client endpoint over http:// sends prompts and responses (and often API keys) in cleartext, exposing them to interception. Use https for the base_url.
Context: base_url="http://localhost"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(llm-client-insecure-http-python)


[warning] 1202-1202: Configuring an LLM/agent client endpoint over http:// sends prompts and responses (and often API keys) in cleartext, exposing them to interception. Use https for the base_url.
Context: base_url="http://localhost"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(llm-client-insecure-http-python)


[warning] 1241-1241: Configuring an LLM/agent client endpoint over http:// sends prompts and responses (and often API keys) in cleartext, exposing them to interception. Use https for the base_url.
Context: base_url="http://localhost"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(llm-client-insecure-http-python)


[warning] 763-763: Do not make http calls without encryption
Context: "http://untrusted.example"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(requests-http)


[info] 442-442: use jsonify instead of json.dumps for JSON output
Context: json.dumps(schema_contract, sort_keys=True, separators=(",", ":"))
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)

mcp/src/aiq_mcp/server.py

[warning] 78-78: Do not make http calls without encryption
Context: "http://[::1]:*"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(requests-http)


[warning] 79-79: Do not make http calls without encryption
Context: "http://0.0.0.0:*"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(requests-http)

mcp/scripts/check_license_inventory.py

[info] 173-173: use jsonify instead of json.dumps for JSON output
Context: json.dumps(payload, sort_keys=True, separators=(",", ":"))
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)


[info] 445-445: use jsonify instead of json.dumps for JSON output
Context: json.dumps(inventory, indent=2, sort_keys=True)
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)


[info] 446-446: use jsonify instead of json.dumps for JSON output
Context: json.dumps(validation, sort_keys=True)
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)

🪛 Checkov (3.3.8)
mcp/Dockerfile

[low] 10-10: Ensure the base image uses a non latest version tag

(CKV_DOCKER_7)

🪛 Hadolint (2.14.0)
mcp/Dockerfile

[warning] 16-16: Pin versions in apt get install. Instead of apt-get install <package> use apt-get install <package>=<version>

(DL3008)


[warning] 64-64: Pin versions in apt get install. Instead of apt-get install <package> use apt-get install <package>=<version>

(DL3008)

🪛 OpenGrep (1.25.0)
mcp/tests/test_checkpoint_todos.py

[ERROR] 426-426: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)

mcp/tests/test_client_session_integration.py

[ERROR] 510-510: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)

mcp/tests/test_postgres_job_store.py

[ERROR] 646-646: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)

mcp/src/aiq_mcp/job_store.py

[ERROR] 121-137: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)


[ERROR] 142-154: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)


[ERROR] 166-181: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)


[ERROR] 186-197: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)


[ERROR] 229-232: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)


[ERROR] 277-277: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)


[ERROR] 282-293: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)


[ERROR] 297-297: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)


[ERROR] 298-307: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)


[ERROR] 308-326: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)


[ERROR] 327-329: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)


[ERROR] 330-332: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)


[ERROR] 333-333: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)


[ERROR] 334-336: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)


[ERROR] 337-339: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)


[ERROR] 340-348: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)


[ERROR] 349-357: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)

🪛 SkillSpector (2.3.11)
.agents/skills/aiq-release-qa/SKILL.md

[error] 112: [PE3] Credential Access: Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Remediation: Remove references to credential paths. Use environment variables or secrets managers. For docs, use placeholder paths (e.g., /path/to/config). Never load .env or token files in production code paths.

(Privilege Escalation (PE3))


[error] 112: [PE3] Credential Access: Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Remediation: Remove references to credential paths. Use environment variables or secrets managers. For docs, use placeholder paths (e.g., /path/to/config). Never load .env or token files in production code paths.

(Privilege Escalation (PE3))


[error] 112: [PE3] Credential Access: Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Remediation: Remove references to credential paths. Use environment variables or secrets managers. For docs, use placeholder paths (e.g., /path/to/config). Never load .env or token files in production code paths.

(Privilege Escalation (PE3))

🪛 SQLFluff (4.2.2)
mcp/deploy/init-mcp-db.sql

[error] 43-43: CREATE INDEX should use CONCURRENTLY to avoid locking the table during the build.

(PG01)


[error] 44-44: CREATE INDEX should use CONCURRENTLY to avoid locking the table during the build.

(PG01)


[error] 45-45: CREATE INDEX should use CONCURRENTLY to avoid locking the table during the build.

(PG01)


[error] 46-46: CREATE INDEX should use CONCURRENTLY to avoid locking the table during the build.

(PG01)

Comment thread mcp/README.md Outdated
Comment thread mcp/README.md
Comment thread mcp/REFERENCE_PARITY.md
Comment thread mcp/scripts/check_license_inventory.py
Comment thread mcp/scripts/protocol_smoke.py
Comment thread mcp/src/aiq_mcp/job_store.py Outdated
Comment thread mcp/src/aiq_mcp/jobs.py Outdated
Comment thread mcp/src/aiq_mcp/jobs.py
Comment thread mcp/src/aiq_mcp/workflow_runner.py
Comment thread mcp/tests/test_postgres_job_store.py
tanleach added 2 commits July 14, 2026 13:23
Signed-off-by: Tanner Leach <tleach@nvidia.com>
Signed-off-by: Tanner Leach <tleach@nvidia.com>
@tanleach tanleach self-assigned this Jul 14, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/aiq_agent/agents/chat_researcher/agent.py (1)

551-568: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Reset turn-scoped state for dict inputs.
run() accepts raw dict state, but this branch forwards workflow_outcome and shallow_result unchanged. With a checkpointed thread_id, LangGraph merges partial dict input into the prior snapshot, so omitted keys can carry a previous turn’s failure state into the next response. Mirror the ChatResearcherState branch here.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/aiq_agent/agents/chat_researcher/agent.py` around lines 551 - 568, Update
the dict-input branch in run() to explicitly reset turn-scoped shallow_result
and workflow_outcome to None, matching the ChatResearcherState branch before
LangGraph merges checkpointed state. Preserve the existing messages extraction
and other dict-provided values.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/aiq_agent/agents/chat_researcher/agent.py`:
- Around line 551-568: Update the dict-input branch in run() to explicitly reset
turn-scoped shallow_result and workflow_outcome to None, matching the
ChatResearcherState branch before LangGraph merges checkpointed state. Preserve
the existing messages extraction and other dict-provided values.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 4114dfdd-c6be-48b2-92b1-ab278af1e6ab

📥 Commits

Reviewing files that changed from the base of the PR and between 49faee5 and 77144a4.

📒 Files selected for processing (14)
  • mcp/REFERENCE_PARITY.md
  • mcp/src/aiq_mcp/jobs.py
  • mcp/src/aiq_mcp/workflow_runner.py
  • mcp/tests/test_client_session_integration.py
  • mcp/tests/test_jobs.py
  • mcp/tests/test_postgres_job_store.py
  • mcp/tests/test_workflow_runner.py
  • src/aiq_agent/agents/chat_researcher/agent.py
  • src/aiq_agent/agents/chat_researcher/models/__init__.py
  • src/aiq_agent/agents/chat_researcher/models/result.py
  • src/aiq_agent/agents/chat_researcher/models/state.py
  • src/aiq_agent/agents/chat_researcher/register.py
  • tests/aiq_agent/agents/chat_researcher/test_agent.py
  • tests/aiq_agent/agents/chat_researcher/test_register_helpers.py
📜 Review details
🧰 Additional context used
📓 Path-based instructions (7)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Format and lint Python with Ruff using line length 120, target version 3.11, rules E/F/W/I/PL/UP, and single-line imports; avoid reformatting unrelated code.

Files:

  • src/aiq_agent/agents/chat_researcher/models/__init__.py
  • tests/aiq_agent/agents/chat_researcher/test_agent.py
  • src/aiq_agent/agents/chat_researcher/models/result.py
  • src/aiq_agent/agents/chat_researcher/models/state.py
  • src/aiq_agent/agents/chat_researcher/register.py
  • mcp/src/aiq_mcp/workflow_runner.py
  • src/aiq_agent/agents/chat_researcher/agent.py
  • mcp/tests/test_jobs.py
  • mcp/tests/test_client_session_integration.py
  • tests/aiq_agent/agents/chat_researcher/test_register_helpers.py
  • mcp/tests/test_workflow_runner.py
  • mcp/src/aiq_mcp/jobs.py
  • mcp/tests/test_postgres_job_store.py
src/aiq_agent/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

src/aiq_agent/**/*.py: Register new data sources in data_source_registry so the UI can toggle them.
Respect authenticated data sources by honoring requires_auth, per-user token pass-through, backend token validators, and owner guardrails before loading protected report or artifact context.
Do not weaken or bypass AuthMiddleware, token validators, or authentication gating without prior design discussion.

Files:

  • src/aiq_agent/agents/chat_researcher/models/__init__.py
  • src/aiq_agent/agents/chat_researcher/models/result.py
  • src/aiq_agent/agents/chat_researcher/models/state.py
  • src/aiq_agent/agents/chat_researcher/register.py
  • src/aiq_agent/agents/chat_researcher/agent.py
**/*

📄 CodeRabbit inference engine (AGENTS.md)

**/*: Do not edit adjacent repositories; keep changes inside this repository and scope changes in sources/* to the smallest affected package.
Run the narrowest relevant validation command first and broaden testing only when changes cross shared boundaries.
For substantial behavior, authentication, UI, or architecture changes, open a design discussion before coding.
Keep pull requests scoped, avoid unrelated files and generated artifacts, do not include secrets, and provide validation commands and results.
Every commit must use DCO sign-off via git commit -s and contain a valid Signed-off-by trailer.
Treat sources/* as independent packages and prefer the smallest change scoped to the package being modified.

Do not include secrets, credentials, private hostnames, internal-only logs, customer data, or generated local artifacts.

Files:

  • src/aiq_agent/agents/chat_researcher/models/__init__.py
  • mcp/REFERENCE_PARITY.md
  • tests/aiq_agent/agents/chat_researcher/test_agent.py
  • src/aiq_agent/agents/chat_researcher/models/result.py
  • src/aiq_agent/agents/chat_researcher/models/state.py
  • src/aiq_agent/agents/chat_researcher/register.py
  • mcp/src/aiq_mcp/workflow_runner.py
  • src/aiq_agent/agents/chat_researcher/agent.py
  • mcp/tests/test_jobs.py
  • mcp/tests/test_client_session_integration.py
  • tests/aiq_agent/agents/chat_researcher/test_register_helpers.py
  • mcp/tests/test_workflow_runner.py
  • mcp/src/aiq_mcp/jobs.py
  • mcp/tests/test_postgres_job_store.py
**/*.{py,ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{py,ts,tsx,js,jsx}: Never commit secrets, tokens, or environment-specific hostnames; use environment variables and SecretStr, and resolve API keys at runtime.
Never print or log secret values, including in tool output or error messages.
Missing-secret paths must degrade gracefully by stubbing or skipping rather than crashing or leaking information.

Files:

  • src/aiq_agent/agents/chat_researcher/models/__init__.py
  • tests/aiq_agent/agents/chat_researcher/test_agent.py
  • src/aiq_agent/agents/chat_researcher/models/result.py
  • src/aiq_agent/agents/chat_researcher/models/state.py
  • src/aiq_agent/agents/chat_researcher/register.py
  • mcp/src/aiq_mcp/workflow_runner.py
  • src/aiq_agent/agents/chat_researcher/agent.py
  • mcp/tests/test_jobs.py
  • mcp/tests/test_client_session_integration.py
  • tests/aiq_agent/agents/chat_researcher/test_register_helpers.py
  • mcp/tests/test_workflow_runner.py
  • mcp/src/aiq_mcp/jobs.py
  • mcp/tests/test_postgres_job_store.py
**/*.{py,pyi}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.{py,pyi}: Run uv run ruff check . and uv run ruff format --check . for Python changes.
Run uv run pytest and add or update tests for Python behavior changes.

Files:

  • src/aiq_agent/agents/chat_researcher/models/__init__.py
  • tests/aiq_agent/agents/chat_researcher/test_agent.py
  • src/aiq_agent/agents/chat_researcher/models/result.py
  • src/aiq_agent/agents/chat_researcher/models/state.py
  • src/aiq_agent/agents/chat_researcher/register.py
  • mcp/src/aiq_mcp/workflow_runner.py
  • src/aiq_agent/agents/chat_researcher/agent.py
  • mcp/tests/test_jobs.py
  • mcp/tests/test_client_session_integration.py
  • tests/aiq_agent/agents/chat_researcher/test_register_helpers.py
  • mcp/tests/test_workflow_runner.py
  • mcp/src/aiq_mcp/jobs.py
  • mcp/tests/test_postgres_job_store.py
src/aiq_agent/agents/**/*

⚙️ CodeRabbit configuration file

src/aiq_agent/agents/**/*: Review agent changes for research workflow correctness, graph state transitions, prompt/tool contracts,
HITL behavior, and failure handling. Flag changes that weaken source attribution, report generation,
async cancellation, checkpointing, or data-source selection without focused tests and docs.

Files:

  • src/aiq_agent/agents/chat_researcher/models/__init__.py
  • src/aiq_agent/agents/chat_researcher/models/result.py
  • src/aiq_agent/agents/chat_researcher/models/state.py
  • src/aiq_agent/agents/chat_researcher/register.py
  • src/aiq_agent/agents/chat_researcher/agent.py
mcp/**/*.{py,pyi}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

For MCP changes, run the MCP project development dependency setup and uv run --project mcp --extra dev pytest mcp/tests.

Files:

  • mcp/src/aiq_mcp/workflow_runner.py
  • mcp/tests/test_jobs.py
  • mcp/tests/test_client_session_integration.py
  • mcp/tests/test_workflow_runner.py
  • mcp/src/aiq_mcp/jobs.py
  • mcp/tests/test_postgres_job_store.py
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-14T19:25:37.061Z
Learning: Open an issue or discussion before large design changes, public APIs, deployment changes, or contributor workflow changes.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-14T19:25:37.061Z
Learning: Target the `develop` branch unless a maintainer requests a release branch.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-14T19:25:37.061Z
Learning: Make the smallest coherent change and add or update tests for behavior changes.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-14T19:25:37.061Z
Learning: Sign off every commit with `git commit -s`; commits without sign-off may be rejected.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-14T19:25:37.061Z
Learning: Run the narrowest local validation command that covers the change and include exact output or a workflow link in the pull request.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-14T19:25:37.061Z
Learning: Open pull requests into `develop`, complete the PR template with exact validation evidence, and address feedback until required checks and code-owner review pass.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-14T19:25:37.061Z
Learning: Search existing issues and pull requests before opening new work.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-14T19:25:42.163Z
Learning: Use the repository's development and quality workflow: prefer `./scripts/dev.sh` commands or run `pre-commit run --all-files`, `pytest`, and the configured formatters directly.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-14T19:25:52.561Z
Learning: Use the documented `uv` commands to install dependencies, run the full test suite, run coverage, or run targeted tests; the MCP project uses its own environment and lockfile.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-14T19:25:52.561Z
Learning: Refer to each benchmark's README for benchmark-specific instructions and consult the Customization guide when adding evaluation harnesses.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-14T19:25:52.561Z
Learning: For debugging, enable verbose CLI logging or workflow configuration, use Phoenix tracing when configured, and consult the documented troubleshooting steps for import, authentication, tool-discovery, and pre-commit issues.
📚 Learning: 2026-07-06T23:55:42.908Z
Learnt from: cdgamarose-nv
Repo: NVIDIA-AI-Blueprints/aiq PR: 311
File: src/aiq_agent/agents/deep_researcher/prompts/orchestrator.j2:74-81
Timestamp: 2026-07-06T23:55:42.908Z
Learning: In agent test files (e.g., tests/aiq_agent/agents/*/test_agent.py), avoid brittle assertions that match exact substrings from prompt template files (such as *.j2 prompt wording). Prompt wording can change frequently, so instead assert structural/behavioral properties (e.g., that the prompt builder is called, that required sections/fields are present via stable markers, that the model output/agent behavior conforms to an expected schema, or that key actions are taken) rather than matching literal prompt text.

Applied to files:

  • tests/aiq_agent/agents/chat_researcher/test_agent.py
🔇 Additional comments (14)
src/aiq_agent/agents/chat_researcher/models/__init__.py (1)

20-38: LGTM!

src/aiq_agent/agents/chat_researcher/models/result.py (1)

18-49: LGTM!

src/aiq_agent/agents/chat_researcher/models/state.py (1)

30-30: LGTM!

Also applies to: 62-63, 81-81

src/aiq_agent/agents/chat_researcher/agent.py (1)

55-58: LGTM!

Also applies to: 72-73, 172-172, 237-237, 250-250, 263-263, 302-305, 364-391

src/aiq_agent/agents/chat_researcher/register.py (1)

34-34: LGTM!

Also applies to: 43-52, 69-98, 570-570, 588-610, 654-669, 681-684, 704-704, 717-717

tests/aiq_agent/agents/chat_researcher/test_register_helpers.py (1)

18-19: LGTM!

Also applies to: 26-28, 31-44, 46-70

mcp/tests/test_workflow_runner.py (1)

1-31: LGTM!

Also applies to: 93-160

mcp/tests/test_postgres_job_store.py (1)

22-22: LGTM!

Also applies to: 30-54

mcp/REFERENCE_PARITY.md (1)

69-73: LGTM!

tests/aiq_agent/agents/chat_researcher/test_agent.py (1)

25-29: LGTM!

Also applies to: 214-239, 584-585

mcp/tests/test_jobs.py (1)

19-24: LGTM!

Also applies to: 30-47, 59-67, 639-664, 766-798, 994-1016

mcp/tests/test_client_session_integration.py (1)

34-36: LGTM!

Also applies to: 74-88, 447-508

mcp/src/aiq_mcp/jobs.py (1)

27-27: LGTM!

Also applies to: 236-267, 284-292

mcp/src/aiq_mcp/workflow_runner.py (1)

109-132: 🩺 Stability & Availability

No issue: _render_workflow_response() turns a missing workflow_outcome into WorkflowSuccess(result=...), so run_query() cannot return None on the success path.

			> Likely an incorrect or invalid review comment.

@AjayThorve

Copy link
Copy Markdown
Collaborator

/ok to test 77144a4

Signed-off-by: Tanner Leach <tleach@nvidia.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
tests/aiq_agent/agents/chat_researcher/test_agent.py (1)

214-239: 📐 Maintainability & Code Quality | 🔵 Trivial

Run the required Python validation before merge.

Run the narrowest relevant tests first, then uv run ruff check ., uv run ruff format --check ., and uv run pytest; include the exact results in the PR.

As per coding guidelines, Python changes require Ruff and pytest validation. Based on learnings, run the narrowest relevant suite first and include the exact output in the PR.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/aiq_agent/agents/chat_researcher/test_agent.py` around lines 214 - 239,
Run the focused tests covering
test_shallow_research_failure_sets_terminal_outcome first, then execute uv run
ruff check ., uv run ruff format --check ., and uv run pytest; report the exact
results from each command in the PR.

Sources: Coding guidelines, Learnings

src/aiq_agent/agents/chat_researcher/agent.py (1)

570-580: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Reset checkpoint state for dict turns in run().
At src/aiq_agent/agents/chat_researcher/agent.py:570-580, the dict path bypasses the shallow_result / workflow_outcome reset, so a follow-up turn on the same thread can inherit a prior WorkflowFailure. Normalize the dict branch too and add a regression test that calls run() with a dict after a failing turn.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/aiq_agent/agents/chat_researcher/agent.py` around lines 570 - 580, Update
the dict-state branch in run() to normalize turn-boundary checkpoint fields like
shallow_result and workflow_outcome to None, matching the non-dict branch and
preventing prior failures from carrying into follow-up turns. Add a regression
test that runs a failing turn, then calls run() with a dict on the same thread
and verifies the stale failure state is cleared.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/aiq_agent/agents/chat_researcher/agent.py`:
- Around line 410-411: Remove the raw active_report_job_id from the timeout
warning in the report ask exception path; use log_identifier_ref for a redacted
identifier or log only the timeout error type. Extend redaction coverage to the
agent logger so this path verifies the bearer capability is never emitted.

---

Outside diff comments:
In `@src/aiq_agent/agents/chat_researcher/agent.py`:
- Around line 570-580: Update the dict-state branch in run() to normalize
turn-boundary checkpoint fields like shallow_result and workflow_outcome to
None, matching the non-dict branch and preventing prior failures from carrying
into follow-up turns. Add a regression test that runs a failing turn, then calls
run() with a dict on the same thread and verifies the stale failure state is
cleared.

In `@tests/aiq_agent/agents/chat_researcher/test_agent.py`:
- Around line 214-239: Run the focused tests covering
test_shallow_research_failure_sets_terminal_outcome first, then execute uv run
ruff check ., uv run ruff format --check ., and uv run pytest; report the exact
results from each command in the PR.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 07fb75c6-36f1-44b2-a819-76cee67d972f

📥 Commits

Reviewing files that changed from the base of the PR and between 77144a4 and d471432.

📒 Files selected for processing (4)
  • src/aiq_agent/agents/chat_researcher/agent.py
  • src/aiq_agent/agents/chat_researcher/register.py
  • tests/aiq_agent/agents/chat_researcher/test_agent.py
  • tests/aiq_agent/agents/chat_researcher/test_register_helpers.py
📜 Review details
⏰ Context from checks skipped due to timeout. (2)
  • GitHub Check: Run Harbor skill eval
  • GitHub Check: Pytest and Coverage
🧰 Additional context used
📓 Path-based instructions (6)
tests/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Use Ruff for Python linting and formatting with line length 120, target Python 3.11, rules E, F, W, I, PL, UP, and single-line imports via isort force-single-line. Do not reformat unrelated code.

Files:

  • tests/aiq_agent/agents/chat_researcher/test_register_helpers.py
  • tests/aiq_agent/agents/chat_researcher/test_agent.py
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

New tools and data sources must be implemented as NeMo Agent Toolkit functions registered with @register_function; their config schemas must inherit from FunctionBaseConfig.

For Python repository changes, run uv run ruff check ., uv run ruff format --check ., and uv run pytest as applicable.

Files:

  • tests/aiq_agent/agents/chat_researcher/test_register_helpers.py
  • tests/aiq_agent/agents/chat_researcher/test_agent.py
  • src/aiq_agent/agents/chat_researcher/agent.py
  • src/aiq_agent/agents/chat_researcher/register.py
**/*.{py,pyi}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{py,pyi}: Never commit secrets or tokens; use environment variables and SecretStr, and resolve API keys at runtime.
Never print or log secret values, including in tool output or error messages.
Missing-secret paths must degrade gracefully by stubbing or skipping rather than crashing or leaking secrets.
Respect authenticated data sources by honoring requires_auth, per-user token pass-through, and backend token validators; apply owner guardrails before loading protected report or artifact context into an agent.
Do not weaken or bypass AuthMiddleware, validators, or authentication gating without prior design discussion.

Files:

  • tests/aiq_agent/agents/chat_researcher/test_register_helpers.py
  • tests/aiq_agent/agents/chat_researcher/test_agent.py
  • src/aiq_agent/agents/chat_researcher/agent.py
  • src/aiq_agent/agents/chat_researcher/register.py
**/*

📄 CodeRabbit inference engine (AGENTS.md)

**/*: Stay inside this repository and do not edit adjacent repositories. Treat each sources/* package as independent and prefer the smallest package-scoped change.
Run the narrowest relevant validation command first, broadening to the full suite only when a change crosses shared boundaries.
For substantial behavior, authentication, UI, or architecture changes, open a design discussion before coding rather than landing a large unreviewed change.
Keep pull requests scoped: avoid unrelated files, accidental generated artifacts, and secrets, and provide validation evidence with commands and results.
Every commit must be signed off with git commit -s; commits must contain a Signed-off-by trailer.

**/*: Do not include secrets, credentials, private hostnames, internal-only logs, customer data, or generated local artifacts in contributions.
Target the develop branch for pull requests unless a maintainer requests a release branch.
Add or update tests for behavior changes.

Files:

  • tests/aiq_agent/agents/chat_researcher/test_register_helpers.py
  • tests/aiq_agent/agents/chat_researcher/test_agent.py
  • src/aiq_agent/agents/chat_researcher/agent.py
  • src/aiq_agent/agents/chat_researcher/register.py
src/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Use Ruff for Python linting and formatting with line length 120, target Python 3.11, rules E, F, W, I, PL, UP, and single-line imports via isort force-single-line. Do not reformat unrelated code.

Files:

  • src/aiq_agent/agents/chat_researcher/agent.py
  • src/aiq_agent/agents/chat_researcher/register.py
src/aiq_agent/agents/**/*

⚙️ CodeRabbit configuration file

src/aiq_agent/agents/**/*: Review agent changes for research workflow correctness, graph state transitions, prompt/tool contracts,
HITL behavior, and failure handling. Flag changes that weaken source attribution, report generation,
async cancellation, checkpointing, or data-source selection without focused tests and docs.

Files:

  • src/aiq_agent/agents/chat_researcher/agent.py
  • src/aiq_agent/agents/chat_researcher/register.py
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-14T19:58:15.613Z
Learning: Sign off every commit with `git commit -s`; commits without sign-off may be rejected.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-14T19:58:15.613Z
Learning: Run the narrowest relevant local validation before opening a pull request and include the exact output or workflow link in the PR.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-14T19:58:15.613Z
Learning: Open an issue or discussion before large design changes, public APIs, deployment changes, or contributor workflow changes.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-14T19:58:15.613Z
Learning: Use the maintainer-reviewed pull-request workflow and address feedback until required checks and code-owner review pass.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-14T19:58:29.160Z
Learning: Use the documented `uv` commands to synchronize environments and run the main project, coverage, targeted, or MCP test suites.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-14T19:58:29.160Z
Learning: Refer to each benchmark's README for benchmark-specific testing details.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-14T19:58:29.160Z
Learning: Use verbose CLI logging, Phoenix tracing, and the documented troubleshooting steps when debugging.
📚 Learning: 2026-07-06T23:55:42.908Z
Learnt from: cdgamarose-nv
Repo: NVIDIA-AI-Blueprints/aiq PR: 311
File: src/aiq_agent/agents/deep_researcher/prompts/orchestrator.j2:74-81
Timestamp: 2026-07-06T23:55:42.908Z
Learning: In agent test files (e.g., tests/aiq_agent/agents/*/test_agent.py), avoid brittle assertions that match exact substrings from prompt template files (such as *.j2 prompt wording). Prompt wording can change frequently, so instead assert structural/behavioral properties (e.g., that the prompt builder is called, that required sections/fields are present via stable markers, that the model output/agent behavior conforms to an expected schema, or that key actions are taken) rather than matching literal prompt text.

Applied to files:

  • tests/aiq_agent/agents/chat_researcher/test_agent.py
🔇 Additional comments (4)
tests/aiq_agent/agents/chat_researcher/test_register_helpers.py (1)

18-68: LGTM!

Also applies to: 137-152

tests/aiq_agent/agents/chat_researcher/test_agent.py (1)

25-29: LGTM!

Also applies to: 584-594, 607-607, 625-627, 668-668

src/aiq_agent/agents/chat_researcher/agent.py (1)

55-58: LGTM!

Also applies to: 72-75, 172-172, 237-243, 248-255, 261-269, 302-305, 364-391, 404-407, 412-415, 427-428, 443-446, 457-465

src/aiq_agent/agents/chat_researcher/register.py (1)

34-34: LGTM!

Also applies to: 43-52, 64-98, 139-139, 570-570, 588-610, 654-669, 681-684, 704-704, 717-717

Comment thread src/aiq_agent/agents/chat_researcher/agent.py Outdated
tanleach added 9 commits July 14, 2026 16:05
Signed-off-by: Tanner Leach <tleach@nvidia.com>
The per-user MCP tools block imported PerUserMcpSourceUnavailableError inside
the same try that guards the aiq_api imports. In the standalone MCP profile
(which intentionally ships without aiq_api), the first aiq_api import raises
ModuleNotFoundError, and then evaluating `except PerUserMcpSourceUnavailableError`
raises UnboundLocalError, bypassing the broad `except Exception` that was meant
to continue. Result: every shallow query on the standalone MCP server failed
with "Research could not be completed. Please try again."

Resolve the reconnect exception type up front (guarded) and treat a missing
aiq_api as an expected skip, so shallow research proceeds with its base tools.
The per-user reconnect message is preserved when aiq_api is present.

Add register-level regression tests covering both the aiq_api-absent skip path
(previously crashed with UnboundLocalError) and the reconnect path.

Verified live against a standalone MCP container: a shallow query that returned
state="failed" now returns state="complete" with cited results.

Fixes: AIQ-002
Signed-off-by: Tanner Leach <tleach@nvidia.com>
Document source checkout and release container support, mark the locally
buildable MCP wheel as private, and cover the classifier in packaging tests.

Signed-off-by: Tanner Leach <tleach@nvidia.com>
The report job UUID is an opaque bearer capability in the MCP security
model: all callers share the anonymous principal, so anyone holding the
UUID can read or edit that report. Three report follow-up log sites in
the chat researcher logged it verbatim (ask timeout, ask failure, and
edit-submission failure), leaking the capability into logs.

Route the identifier through the existing log_identifier_ref helper so
only a stable sha256:<12hex> correlation ref is logged, matching the
convention already used in register.py and the MCP job runner. A small
None-safe _report_ref wrapper handles the inline path where
active_report_job_id is unset.

Add caplog coverage on all three sites asserting the raw UUID is absent
and the redacted ref is present.

Source: PR NVIDIA-AI-Blueprints#319 review (discussion r3582250506).

Signed-off-by: Tanner Leach <tleach@nvidia.com>
Signed-off-by: Tanner Leach <tleach@nvidia.com>
Signed-off-by: Tanner Leach <tleach@nvidia.com>
The CI postgres service creates a database named aiq_mcp_tests (plural),
but require_test_database_url only accepted the _test suffix, causing all
PostgreSQL-backed tests to error at setup with a ValueError.

Signed-off-by: Tanner Leach <tleach@nvidia.com>
Signed-off-by: Tanner Leach <tleach@nvidia.com>
The MCP job path classified every research query twice: JobManager.submit()
classified to persist depth and choose the poll cadence, then the chat graph
re-classified at its intent_classifier entry point. At temperature 0.5 the
second decision could diverge from the first, so the public job depth /
estimated_duration / poll cadence could describe different work than actually
ran, and every submit paid intent-classifier latency and cost twice.

Make JobManager the single owner of the decision. submit()'s depth is threaded
through _run_job -> run_query into a request-scoped ContextVar
(chat_researcher/preclassification.py); the intent_classifier node reuses it
and returns without calling the LLM. The hook is strictly opt-in: API/CLI
callers never set it, user_intent/depth_decision stay unset, and the
short-circuit never fires for them.

Adds a unit test (node reuses the preset, no LLM call), an MCP consistency
test (classify called once; persisted depth == executed run depth), and a
real-workflow integration test that drives the actual intent_classifier
through nat.Function.ainvoke and proves the preset overrides a divergent LLM
decision with no second classification.

Signed-off-by: Tanner Leach <tleach@nvidia.com>
@tanleach

Copy link
Copy Markdown
Collaborator Author

/ok to test 3be0337

tanleach added 4 commits July 14, 2026 21:03
WorkflowRunner._close_owned_checkpointers() reaches into aiq_agent.common's
private _checkpointers / _postgres_pools dicts to close the handles it created,
reading them via getattr(..., {}). If aiq_agent renamed or removed those private
names, cleanup silently became a no-op and the connections/pools leaked.

Resolve the caches up front and warn (naming the missing cache) when they are
absent, instead of skipping silently. The check runs before the empty-owned-keys
guard so a rename -- which leaves start()'s snapshot empty and would otherwise
bypass detection -- is still surfaced. There is no public cleanup API in
aiq_agent.common to reuse, so warn-only is the intended fallback.

Adds tests: warns when the caches are missing (with and without recorded owned
keys) and stays silent when caches are present but nothing is owned.

Signed-off-by: Tanner Leach <tleach@nvidia.com>
Validate supported-client endpoints before constructing the HTTP client so
credential-bearing, query-token, and fragment URLs cannot be requested or
echoed. Cover accepted and rejected forms and document the constraint.

Fixes: AIQ-007
Signed-off-by: Tanner Leach <tleach@nvidia.com>
The UPDATE+fallback pattern in JobStore.record_poll() fell back to the
unscoped get() when the principal-scoped UPDATE touched zero rows (job
terminal or nonexistent). get() has no AND principal filter, so a
caller holding any job UUID could observe a terminal job owned by a
different principal.

Replace the get() fallback with an inline SELECT that includes AND
principal = \$2, maintaining the same isolation contract as the UPDATE.
get() is intentionally left unscoped — it is an internal/runner path
with no principal-enforcement callers.

Also tighten the existing wrong-principal active-job assertion in the
reconciliation semantics test (record_poll with the wrong principal now
returns None rather than the unguarded row) and add a regression test
for the terminal-state cross-principal case.

Signed-off-by: Tanner Leach <tleach@nvidia.com>
The report-rewriter child job id is the same bearer-capability class as the
chat-researcher report job UUID: in the MCP security model all callers share
the anonymous principal, so anyone holding the UUID can read or edit that
report. The success-path completion log in report_rewriter/agent.py logged it
verbatim on every completed rewrite, leaking the capability into logs.

Route the identifier through the existing log_identifier_ref helper via a
None-safe _job_ref wrapper, so only a stable sha256:<12hex> correlation ref is
logged (falling back to "none" when job_id is unset), matching the redaction
already applied to the chat-researcher report follow-up log sites.

Adds caplog coverage asserting the raw UUID is absent and the redacted ref is
present on the success path, plus a None-job-id case; both proven to fail
against the pre-fix log line.

Source: PR NVIDIA-AI-Blueprints#319 review (AIQ issue 014, follow-up to issue 003).
Signed-off-by: Tanner Leach <tleach@nvidia.com>
@NVIDIA-AI-Blueprints NVIDIA-AI-Blueprints deleted a comment from coderabbitai Bot Jul 15, 2026
Add focused tests for validate_lock_sources in
mcp/scripts/check_license_inventory.py, which enforces the MCP
public-source contract (public PyPI plus the approved editable path
sources). Covers acceptance of the exact approved contract, rejection
of unapproved registries and non-editable or malformed lock sources,
local source-set mismatches, dependency-name canonicalization, and a
regression guard that the committed mcp/uv.lock satisfies the contract.
Pins the current exact-match editable-path behavior as characterization.

Resolves AIQ-011 (PR NVIDIA-AI-Blueprints#319 thread r3580087766).

Signed-off-by: Tanner Leach <tleach@nvidia.com>
@tanleach

Copy link
Copy Markdown
Collaborator Author

/ok to test d90bc8a

@tanleach tanleach requested a review from AjayThorve July 15, 2026 02:22

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
src/aiq_agent/agents/chat_researcher/agent.py (1)

581-583: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Reset transient outcomes for dictionary inputs.

Dictionary callers bypass the per-turn reset at Lines 590-591. A checkpointed prior WorkflowFailure can therefore survive into a successful turn and be persisted as a failed MCP job. Copy the mapping and clear both transient fields.

Proposed fix
 if isinstance(state, dict):
-    input_state = state
+    input_state = {
+        **state,
+        "shallow_result": None,
+        "workflow_outcome": None,
+    }
     messages = state.get("messages", [])
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/aiq_agent/agents/chat_researcher/agent.py` around lines 581 - 583, Update
the dictionary-input branch in the agent state handling to copy the incoming
mapping rather than mutate or reuse it directly, then clear both transient
outcome fields before processing the turn. Preserve the existing messages
extraction while ensuring prior WorkflowFailure state cannot be carried into
persistence after a successful turn.
.github/workflows/ci.yml (1)

230-236: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Run the import canary in the production MCP environment.

This invokes the dependency script without --verify-imports, so the --no-dev --no-editable closure can still pass while imports or entry points fail at runtime. Add the flag to Line 236 and retain it in CI.

As per path instructions, automation changes require reproducible uv setup and consistency with the documented validation matrix.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci.yml around lines 230 - 236, Update the production MCP
environment validation in the workflow step named “Create MCP production
environment” to invoke mcp/scripts/check_runtime_dependencies.py with the
--verify-imports flag, preserving the existing frozen, no-dev,
no-default-groups, and no-editable uv setup.

Source: Path instructions

mcp/src/aiq_mcp/workflow_runner.py (1)

77-90: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Redact checkpointer keys in cleanup logs.

key is the job-backed conversation_id; Lines 85 and 90 log it verbatim, bypassing the redaction already used by run_query. Use log_identifier_ref(key) in both messages.

Proposed fix
         checkpointers, postgres_pools = caches
         for key in list(self._owned_checkpointer_keys):
+            key_ref = log_identifier_ref(key)
             checkpointer = checkpointers.pop(key, None)
             ...
-                    logger.debug("Closed SQLite checkpointer connection: %s", key)
+                    logger.debug("Closed SQLite checkpointer connection: %s", key_ref)
             ...
-                logger.debug("Closed Postgres checkpointer pool: %s", key)
+                logger.debug("Closed Postgres checkpointer pool: %s", key_ref)

Based on PR objectives, job UUIDs are bearer capabilities. As per coding guidelines, “Never print or log secret values, including through tool output or error messages.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mcp/src/aiq_mcp/workflow_runner.py` around lines 77 - 90, Update the cleanup
debug logs in the checkpointer cleanup loop to redact the job-backed key before
logging it. Specifically, in the messages associated with closing SQLite
connections and PostgreSQL pools, replace the raw key formatting with the
existing log_identifier_ref(key) helper, matching the redaction used by
run_query.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/source/deployment/docker-build.md`:
- Around line 67-69: Update the deployment documentation’s MCP sync command to
explicitly include the --frozen flag before --project /app/mcp, preserving the
existing explanation that the build uses mcp/uv.lock.

In `@mcp/src/aiq_mcp/job_store.py`:
- Around line 307-333: Update the cleanup query in the job-store sweep to select
only terminal jobs before deleting checkpoint state; do not clean up expired
jobs whose workflow is still running. Preserve the existing locked, batched
deletion flow for terminal jobs and add an integration test proving active
workflows can still write checkpoints without their state being deleted.

In `@src/aiq_agent/agents/shallow_researcher/register.py`:
- Around line 150-163: Separate the top-level aiq_api import from the
open_per_user_mcp_tools call in the shallow researcher setup. Only treat a
ModuleNotFoundError proving aiq_api itself is unavailable as the
standalone-profile fallback; let ModuleNotFoundError or other failures from
open_per_user_mcp_tools follow the existing reconnect/error handling, preserving
requires_auth and authentication gating. Add a regression test covering
open_per_user_mcp_tools raising ModuleNotFoundError.

---

Outside diff comments:
In @.github/workflows/ci.yml:
- Around line 230-236: Update the production MCP environment validation in the
workflow step named “Create MCP production environment” to invoke
mcp/scripts/check_runtime_dependencies.py with the --verify-imports flag,
preserving the existing frozen, no-dev, no-default-groups, and no-editable uv
setup.

In `@mcp/src/aiq_mcp/workflow_runner.py`:
- Around line 77-90: Update the cleanup debug logs in the checkpointer cleanup
loop to redact the job-backed key before logging it. Specifically, in the
messages associated with closing SQLite connections and PostgreSQL pools,
replace the raw key formatting with the existing log_identifier_ref(key) helper,
matching the redaction used by run_query.

In `@src/aiq_agent/agents/chat_researcher/agent.py`:
- Around line 581-583: Update the dictionary-input branch in the agent state
handling to copy the incoming mapping rather than mutate or reuse it directly,
then clear both transient outcome fields before processing the turn. Preserve
the existing messages extraction while ensuring prior WorkflowFailure state
cannot be carried into persistence after a successful turn.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: b32ba7ee-36d3-4551-bb3f-f5ce3765489d

📥 Commits

Reviewing files that changed from the base of the PR and between d471432 and d90bc8a.

⛔ Files ignored due to path filters (1)
  • mcp/uv.lock is excluded by !**/*.lock
📒 Files selected for processing (31)
  • .github/workflows/ci.yml
  • README.md
  • docs/source/deployment/docker-build.md
  • docs/source/integration/mcp-server.md
  • mcp/README.md
  • mcp/SECURITY.md
  • mcp/pyproject.toml
  • mcp/scripts/protocol_smoke.py
  • mcp/src/aiq_mcp/db_url.py
  • mcp/src/aiq_mcp/job_store.py
  • mcp/src/aiq_mcp/jobs.py
  • mcp/src/aiq_mcp/workflow_runner.py
  • mcp/tests/test_checkpoint_todos.py
  • mcp/tests/test_client_session_integration.py
  • mcp/tests/test_config_and_packaging.py
  • mcp/tests/test_db_url.py
  • mcp/tests/test_deployment_assets.py
  • mcp/tests/test_jobs.py
  • mcp/tests/test_postgres_job_store.py
  • mcp/tests/test_preclassification_integration.py
  • mcp/tests/test_release_checks.py
  • mcp/tests/test_workflow_runner.py
  • src/aiq_agent/agents/chat_researcher/agent.py
  • src/aiq_agent/agents/chat_researcher/nodes/intent_classifier.py
  • src/aiq_agent/agents/chat_researcher/preclassification.py
  • src/aiq_agent/agents/report_rewriter/agent.py
  • src/aiq_agent/agents/shallow_researcher/register.py
  • tests/aiq_agent/agents/chat_researcher/nodes/test_intent_classifier.py
  • tests/aiq_agent/agents/chat_researcher/test_agent.py
  • tests/aiq_agent/agents/report_rewriter/test_agent.py
  • tests/aiq_agent/agents/shallow_researcher/test_register_per_user_mcp.py
📜 Review details
🧰 Additional context used
📓 Path-based instructions (10)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Format and lint Python with Ruff using line length 120, target Python 3.11, rule sets E, F, W, I, PL, UP, and single-line imports; avoid reformatting unrelated code.
Never print or log secret values, including through tool output or error messages.
Missing-secret paths must degrade gracefully by stubbing or skipping rather than crashing or leaking values.

For Python changes, run uv run ruff check ., uv run ruff format --check ., and uv run pytest as applicable.

Files:

  • src/aiq_agent/agents/chat_researcher/nodes/intent_classifier.py
  • src/aiq_agent/agents/report_rewriter/agent.py
  • src/aiq_agent/agents/chat_researcher/preclassification.py
  • mcp/tests/test_preclassification_integration.py
  • mcp/src/aiq_mcp/db_url.py
  • tests/aiq_agent/agents/report_rewriter/test_agent.py
  • tests/aiq_agent/agents/chat_researcher/nodes/test_intent_classifier.py
  • mcp/tests/test_db_url.py
  • tests/aiq_agent/agents/chat_researcher/test_agent.py
  • tests/aiq_agent/agents/shallow_researcher/test_register_per_user_mcp.py
  • mcp/tests/test_workflow_runner.py
  • mcp/tests/test_config_and_packaging.py
  • mcp/scripts/protocol_smoke.py
  • mcp/src/aiq_mcp/workflow_runner.py
  • src/aiq_agent/agents/shallow_researcher/register.py
  • src/aiq_agent/agents/chat_researcher/agent.py
  • mcp/tests/test_deployment_assets.py
  • mcp/tests/test_release_checks.py
  • mcp/tests/test_jobs.py
  • mcp/tests/test_client_session_integration.py
  • mcp/src/aiq_mcp/jobs.py
  • mcp/src/aiq_mcp/job_store.py
  • mcp/tests/test_checkpoint_todos.py
  • mcp/tests/test_postgres_job_store.py
**/*.{py,yml,yaml}

📄 CodeRabbit inference engine (AGENTS.md)

Register every new data source in data_source_registry so the UI can toggle it.

Files:

  • src/aiq_agent/agents/chat_researcher/nodes/intent_classifier.py
  • src/aiq_agent/agents/report_rewriter/agent.py
  • src/aiq_agent/agents/chat_researcher/preclassification.py
  • mcp/tests/test_preclassification_integration.py
  • mcp/src/aiq_mcp/db_url.py
  • tests/aiq_agent/agents/report_rewriter/test_agent.py
  • tests/aiq_agent/agents/chat_researcher/nodes/test_intent_classifier.py
  • mcp/tests/test_db_url.py
  • tests/aiq_agent/agents/chat_researcher/test_agent.py
  • tests/aiq_agent/agents/shallow_researcher/test_register_per_user_mcp.py
  • mcp/tests/test_workflow_runner.py
  • mcp/tests/test_config_and_packaging.py
  • mcp/scripts/protocol_smoke.py
  • mcp/src/aiq_mcp/workflow_runner.py
  • src/aiq_agent/agents/shallow_researcher/register.py
  • src/aiq_agent/agents/chat_researcher/agent.py
  • mcp/tests/test_deployment_assets.py
  • mcp/tests/test_release_checks.py
  • mcp/tests/test_jobs.py
  • mcp/tests/test_client_session_integration.py
  • mcp/src/aiq_mcp/jobs.py
  • mcp/src/aiq_mcp/job_store.py
  • mcp/tests/test_checkpoint_todos.py
  • mcp/tests/test_postgres_job_store.py
src/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.py: Respect authenticated data sources by honoring requires_auth, per-user token pass-through, and backend token validators; apply owner guardrails before loading protected report or artifact context into an agent.
Do not weaken or bypass AuthMiddleware, validators, or authentication gating without prior design discussion.

Files:

  • src/aiq_agent/agents/chat_researcher/nodes/intent_classifier.py
  • src/aiq_agent/agents/report_rewriter/agent.py
  • src/aiq_agent/agents/chat_researcher/preclassification.py
  • src/aiq_agent/agents/shallow_researcher/register.py
  • src/aiq_agent/agents/chat_researcher/agent.py
**/*

📄 CodeRabbit inference engine (AGENTS.md)

**/*: Stay within this repository and do not edit adjacent repositories; treat each sources/* package as independent and prefer the smallest package-scoped change.
Run the narrowest relevant validation command first and broaden to the full suite only when a change crosses shared boundaries.
Update documentation and seek a design discussion before coding substantial behavior, authentication, UI, or architecture changes.
Keep pull requests scoped: avoid unrelated files, generated artifacts, and secrets, and provide validation commands and results.
Every commit must use DCO sign-off via git commit -s and contain a Signed-off-by trailer.
Load the relevant task-specific maintainer skill from .agents/skills/ before starting a workflow it covers; do not treat API-consumer skills in skills/ as an in-product runtime.

Do not include secrets, credentials, private hostnames, internal-only logs, customer data, or generated local artifacts.

Files:

  • src/aiq_agent/agents/chat_researcher/nodes/intent_classifier.py
  • src/aiq_agent/agents/report_rewriter/agent.py
  • src/aiq_agent/agents/chat_researcher/preclassification.py
  • mcp/tests/test_preclassification_integration.py
  • mcp/src/aiq_mcp/db_url.py
  • README.md
  • mcp/README.md
  • tests/aiq_agent/agents/report_rewriter/test_agent.py
  • tests/aiq_agent/agents/chat_researcher/nodes/test_intent_classifier.py
  • mcp/tests/test_db_url.py
  • tests/aiq_agent/agents/chat_researcher/test_agent.py
  • tests/aiq_agent/agents/shallow_researcher/test_register_per_user_mcp.py
  • mcp/SECURITY.md
  • mcp/tests/test_workflow_runner.py
  • mcp/tests/test_config_and_packaging.py
  • docs/source/deployment/docker-build.md
  • mcp/scripts/protocol_smoke.py
  • mcp/src/aiq_mcp/workflow_runner.py
  • src/aiq_agent/agents/shallow_researcher/register.py
  • docs/source/integration/mcp-server.md
  • mcp/pyproject.toml
  • src/aiq_agent/agents/chat_researcher/agent.py
  • mcp/tests/test_deployment_assets.py
  • mcp/tests/test_release_checks.py
  • mcp/tests/test_jobs.py
  • mcp/tests/test_client_session_integration.py
  • mcp/src/aiq_mcp/jobs.py
  • mcp/src/aiq_mcp/job_store.py
  • mcp/tests/test_checkpoint_todos.py
  • mcp/tests/test_postgres_job_store.py
src/aiq_agent/agents/**/*

⚙️ CodeRabbit configuration file

src/aiq_agent/agents/**/*: Review agent changes for research workflow correctness, graph state transitions, prompt/tool contracts,
HITL behavior, and failure handling. Flag changes that weaken source attribution, report generation,
async cancellation, checkpointing, or data-source selection without focused tests and docs.

Files:

  • src/aiq_agent/agents/chat_researcher/nodes/intent_classifier.py
  • src/aiq_agent/agents/report_rewriter/agent.py
  • src/aiq_agent/agents/chat_researcher/preclassification.py
  • src/aiq_agent/agents/shallow_researcher/register.py
  • src/aiq_agent/agents/chat_researcher/agent.py
mcp/**/*.py

📄 CodeRabbit inference engine (CONTRIBUTING.md)

For changes under mcp/, run the MCP project's development dependency setup and uv run --project mcp --extra dev pytest mcp/tests.

Files:

  • mcp/tests/test_preclassification_integration.py
  • mcp/src/aiq_mcp/db_url.py
  • mcp/tests/test_db_url.py
  • mcp/tests/test_workflow_runner.py
  • mcp/tests/test_config_and_packaging.py
  • mcp/scripts/protocol_smoke.py
  • mcp/src/aiq_mcp/workflow_runner.py
  • mcp/tests/test_deployment_assets.py
  • mcp/tests/test_release_checks.py
  • mcp/tests/test_jobs.py
  • mcp/tests/test_client_session_integration.py
  • mcp/src/aiq_mcp/jobs.py
  • mcp/src/aiq_mcp/job_store.py
  • mcp/tests/test_checkpoint_todos.py
  • mcp/tests/test_postgres_job_store.py
{docs/**,README.md,CONTRIBUTING.md,SECURITY.md,CODE-OF-CONDUCT.md}

⚙️ CodeRabbit configuration file

{docs/**,README.md,CONTRIBUTING.md,SECURITY.md,CODE-OF-CONDUCT.md}: Review documentation for command accuracy, branch-name consistency, current CI and copy-pr-bot behavior, public
vs internal boundary clarity, stale examples, and links that no longer match the repository layout.

Files:

  • README.md
  • docs/source/deployment/docker-build.md
  • docs/source/integration/mcp-server.md
docs/source/**/*

📄 CodeRabbit inference engine (AGENTS.md)

Update documentation under docs/source/ when behavior, configuration, or workflows change; keep documentation canonical rather than duplicating full pages in skills.

Files:

  • docs/source/deployment/docker-build.md
  • docs/source/integration/mcp-server.md
**/*.{toml,lock}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Dependency changes must leave both project locks current; validate with uv lock --check and uv lock --project mcp --check.

Files:

  • mcp/pyproject.toml
{.github/**,ci/**,.pre-commit-config.yaml,pyproject.toml,uv.lock,mcp/pyproject.toml,mcp/uv.lock}

⚙️ CodeRabbit configuration file

{.github/**,ci/**,.pre-commit-config.yaml,pyproject.toml,uv.lock,mcp/pyproject.toml,mcp/uv.lock}: Review automation and packaging changes for least-privilege permissions, pinned versions where appropriate,
copy-pr-bot pull-request/ branch behavior, reproducible uv/npm setup, secret handling, and consistency with
the documented validation matrix.

Files:

  • mcp/pyproject.toml
  • .github/workflows/ci.yml
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-15T10:58:10.011Z
Learning: Add or update tests for behavior changes.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-15T10:58:10.011Z
Learning: Sign off every commit with `git commit -s`; commits without sign-off may be rejected.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-15T10:58:10.011Z
Learning: Open an issue or discussion before large design changes, public APIs, deployment changes, or contributor workflow changes.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-15T10:58:14.203Z
Learning: When the helper script is unavailable, run `pre-commit run --all-files`, `pytest`, and the configured formatters directly.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-15T10:58:14.203Z
Learning: Run `pre-commit run --all-files` to execute repository-wide checks, including Ruff, lock checks, secret detection, notebook output clearing, and Markdown link validation.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-15T10:58:19.774Z
Learning: Create focused branches from `develop` for changes, add or update tests, and open pull requests against `develop` unless targeting a release branch is explicitly requested by a maintainer.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-15T10:58:19.774Z
Learning: Run the narrowest relevant local validation checks for each change and record the exact commands in the pull request description.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-15T10:58:19.774Z
Learning: For general project changes, run `uv sync --group dev`, `uv run ruff check .`, `uv run ruff format --check .`, and `uv run pytest`.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-15T10:58:19.774Z
Learning: All contributors must sign off their commits using the Developer's Certificate of Origin, for example with `git commit -s -m "Your message"`.
Learnt from: CR
Repo: NVIDIA-AI-Blueprints/aiq

Timestamp: 2026-07-15T10:58:19.774Z
Learning: Contributors certify that they have the right to submit their contribution under the applicable open-source license and acknowledge that contribution records, including sign-off personal information, are public and maintained indefinitely.
📚 Learning: 2026-07-06T23:55:42.908Z
Learnt from: cdgamarose-nv
Repo: NVIDIA-AI-Blueprints/aiq PR: 311
File: src/aiq_agent/agents/deep_researcher/prompts/orchestrator.j2:74-81
Timestamp: 2026-07-06T23:55:42.908Z
Learning: In agent test files (e.g., tests/aiq_agent/agents/*/test_agent.py), avoid brittle assertions that match exact substrings from prompt template files (such as *.j2 prompt wording). Prompt wording can change frequently, so instead assert structural/behavioral properties (e.g., that the prompt builder is called, that required sections/fields are present via stable markers, that the model output/agent behavior conforms to an expected schema, or that key actions are taken) rather than matching literal prompt text.

Applied to files:

  • tests/aiq_agent/agents/report_rewriter/test_agent.py
  • tests/aiq_agent/agents/chat_researcher/test_agent.py
🪛 ast-grep (0.44.1)
mcp/tests/test_deployment_assets.py

[warning] 176-176: Do not make http calls without encryption
Context: "http://[::1]:9001/mcp"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(requests-http)


[warning] 176-176: Do not make http calls without encryption
Context: "http://[::1]:9001/health"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(requests-http)


[warning] 192-192: Do not make http calls without encryption
Context: "http://alice@example.com/mcp"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(requests-http)


[error] 250-255: Command coming from incoming request
Context: subprocess.run(
[sys.executable, str(_SMOKE_SCRIPT), "--url", endpoint, "--health-timeout", "0.01"],
check=False,
capture_output=True,
text=True,
)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(subprocess-from-request)

🪛 OpenGrep (1.25.0)
mcp/src/aiq_mcp/job_store.py

[ERROR] 324-327: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)


[ERROR] 329-332: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)

🔇 Additional comments (27)
src/aiq_agent/agents/chat_researcher/nodes/intent_classifier.py (1)

37-37: LGTM!

Also applies to: 110-120

src/aiq_agent/agents/report_rewriter/agent.py (1)

28-44: LGTM!

Also applies to: 193-193

src/aiq_agent/agents/chat_researcher/preclassification.py (1)

31-57: LGTM!

mcp/tests/test_preclassification_integration.py (1)

33-102: LGTM!

tests/aiq_agent/agents/report_rewriter/test_agent.py (1)

7-15: LGTM!

Also applies to: 207-254

tests/aiq_agent/agents/chat_researcher/nodes/test_intent_classifier.py (1)

29-29: LGTM!

Also applies to: 499-533

tests/aiq_agent/agents/chat_researcher/test_agent.py (1)

18-18: LGTM!

Also applies to: 31-31, 219-241, 586-729

src/aiq_agent/agents/chat_researcher/agent.py (1)

49-74: LGTM!

Also applies to: 183-183, 248-248, 261-261, 274-274, 313-316, 375-476

mcp/src/aiq_mcp/db_url.py (1)

9-10: LGTM!

Also applies to: 25-35

README.md (1)

278-278: LGTM!

Also applies to: 340-360

mcp/README.md (1)

15-24: LGTM!

Also applies to: 90-100, 123-129, 159-164

mcp/tests/test_db_url.py (1)

32-59: LGTM!

mcp/src/aiq_mcp/job_store.py (1)

76-82: LGTM!

Also applies to: 280-293

mcp/tests/test_checkpoint_todos.py (1)

36-36: LGTM!

Also applies to: 421-467

mcp/tests/test_postgres_job_store.py (1)

24-24: LGTM!

Also applies to: 51-55, 264-325, 690-810

.github/workflows/ci.yml (1)

267-324: LGTM!

mcp/tests/test_workflow_runner.py (1)

196-249: LGTM!

mcp/scripts/protocol_smoke.py (1)

33-34: LGTM!

Also applies to: 58-65

mcp/tests/test_deployment_assets.py (1)

163-267: LGTM!

mcp/SECURITY.md (1)

93-96: LGTM!

Also applies to: 126-135

mcp/tests/test_config_and_packaging.py (1)

128-128: LGTM!

docs/source/integration/mcp-server.md (1)

39-47: LGTM!

Also applies to: 259-260

mcp/pyproject.toml (1)

20-20: LGTM!

Also applies to: 59-59

mcp/tests/test_release_checks.py (1)

24-25: LGTM!

Also applies to: 243-358

mcp/tests/test_jobs.py (1)

48-53: LGTM!

Also applies to: 62-64, 244-277, 681-682

mcp/tests/test_client_session_integration.py (1)

38-38: LGTM!

Also applies to: 75-75, 84-84, 581-581, 593-593

mcp/src/aiq_mcp/jobs.py (1)

179-179: LGTM!

Also applies to: 236-236, 249-251

Comment on lines +67 to +69
That builder syncs the frozen MCP project (`uv sync --project /app/mcp`) from
`mcp/uv.lock`, independently of the root image. The root image stays within
NAT's `cryptography<47` constraint; the audited MCP container profile pins

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Show the actual frozen sync command.

The parenthesized command omits --frozen while describing a frozen build. Document uv sync --frozen --project /app/mcp so readers do not reproduce a lock-mutating build path.

Proposed fix
-That builder syncs the frozen MCP project (`uv sync --project /app/mcp`) from
+That builder syncs the frozen MCP project (`uv sync --frozen --project /app/mcp`) from
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
That builder syncs the frozen MCP project (`uv sync --project /app/mcp`) from
`mcp/uv.lock`, independently of the root image. The root image stays within
NAT's `cryptography<47` constraint; the audited MCP container profile pins
That builder syncs the frozen MCP project (`uv sync --frozen --project /app/mcp`) from
`mcp/uv.lock`, independently of the root image. The root image stays within
NAT's `cryptography<47` constraint; the audited MCP container profile pins
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/source/deployment/docker-build.md` around lines 67 - 69, Update the
deployment documentation’s MCP sync command to explicitly include the --frozen
flag before --project /app/mcp, preserving the existing explanation that the
build uses mcp/uv.lock.

Source: Path instructions

Comment thread mcp/src/aiq_mcp/job_store.py
Comment on lines +150 to 163
except ImportError:
# Standalone MCP profile without aiq_api: expected — continue with base tools.
logger.debug("aiq_api unavailable; skipping per-user MCP tools for shallow research")
except Exception as exc:
if PerUserMcpSourceUnavailableError is not None and isinstance(
exc, PerUserMcpSourceUnavailableError
):
# The user explicitly selected a protected source we can't resolve
# (e.g. token expired). Surface a reconnect message instead of
# silently answering without it.
from langchain_core.messages import AIMessage

return ShallowResearchAgentState(messages=state.messages + [AIMessage(content=str(exc))])
logger.exception("Failed to resolve per-user MCP tools for shallow research; continuing")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Only skip when aiq_api itself is absent.

This try also awaits open_per_user_mcp_tools, so an ImportError from a selected connector or auth dependency is treated as the standalone profile and the request proceeds without its selected protected source. Separate imports from tool resolution; only downgrade ModuleNotFoundError for top-level aiq_api, and surface later failures as reconnect/error states. Add a regression test where open_per_user_mcp_tools raises ModuleNotFoundError.

As per coding guidelines, authenticated data sources must honor requires_auth and authentication gating.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/aiq_agent/agents/shallow_researcher/register.py` around lines 150 - 163,
Separate the top-level aiq_api import from the open_per_user_mcp_tools call in
the shallow researcher setup. Only treat a ModuleNotFoundError proving aiq_api
itself is unavailable as the standalone-profile fallback; let
ModuleNotFoundError or other failures from open_per_user_mcp_tools follow the
existing reconnect/error handling, preserving requires_auth and authentication
gating. Add a regression test covering open_per_user_mcp_tools raising
ModuleNotFoundError.

Source: Coding guidelines

Signed-off-by: Tanner Leach <tleach@nvidia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants